<?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=SignpostMarv+Martin</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=SignpostMarv+Martin"/>
	<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/wiki/Special:Contributions/SignpostMarv_Martin"/>
	<updated>2026-07-23T13:53:49Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Template_talk:OptiPNG_FTW!&amp;diff=1188165</id>
		<title>Template talk:OptiPNG FTW!</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Template_talk:OptiPNG_FTW!&amp;diff=1188165"/>
		<updated>2014-03-08T00:43:04Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: note on zopflipng&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== optipng vs zopflipng ==&lt;br /&gt;
I&#039;ve done a little experiment with [https://code.google.com/p/zopfli/source/browse/README.zopflipng Google&#039;s zopflipng tool]; Although zopflipng produces smaller files than optipng, it&#039;s likely not worth the user&#039;s time to run something as picky as `zopflipng --iterations=1024 --splitting=3 --filters=01234mepb` (which took approx 50 minutes to execute on [[:File:WOOLYBEAR INTERSECTION.png|WOOLYBEAR INTERSECTION.png]]) for this wiki.&lt;br /&gt;
&lt;br /&gt;
[[User:SignpostMarv Martin|SignpostMarv Martin]] 16:43, 7 March 2014 (PST)&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=File:WOOLYBEAR_INTERSECTION.png&amp;diff=1188164</id>
		<title>File:WOOLYBEAR INTERSECTION.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=File:WOOLYBEAR_INTERSECTION.png&amp;diff=1188164"/>
		<updated>2014-03-08T00:36:57Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: uploaded a new version of &amp;quot;File:WOOLYBEAR INTERSECTION.png&amp;quot;:&amp;amp;#32;`zopflipng --iterations=1024 --splitting=3 --filters=01234mepb` on previous revision&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Community_Web_Service_APIs&amp;diff=1180525</id>
		<title>Community Web Service APIs</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Community_Web_Service_APIs&amp;diff=1180525"/>
		<updated>2013-08-05T14:25:37Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: fixing typos&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Below are listed third-party web-services and data-feeds provided by communities and businesses related to Second Life.&lt;br /&gt;
:Note: These services are not affiliated with Linden Lab in any way.&lt;br /&gt;
&lt;br /&gt;
Service providers should add their own entries with a brief description and link to further information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;BoxTiny.com&#039;&#039;&#039; - [http://boxtiny.com/ boxtiny.com] - Website with lists of textures indexed for search and download into SL. Community based and supported. All the textures are free and full perm. Look for register page to learn how to register.&lt;br /&gt;
* &#039;&#039;&#039;W-Hat projects&#039;&#039;&#039; - [http://w-hat.com w-hat.com] - An SL group/community that also provides avatar key lookup ([http://w-hat.com/name2key name2key]), persistent database store ([http://w-hat.com/httpdb httpdb]) services.&lt;br /&gt;
* &#039;&#039;&#039;Kubwa.net&#039;&#039;&#039; - [http://kubwa.net/?cmd=name2key Kubwa.net-Name2Key] - An API to allow Name2Key requests from the web or LSL. The database is bot supported and finds everyone&#039;s key.&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:Tips_for_Creating_Heightfields_and_Details_on_Terrain_RAW_Files&amp;diff=1170089</id>
		<title>Talk:Tips for Creating Heightfields and Details on Terrain RAW Files</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:Tips_for_Creating_Heightfields_and_Details_on_Terrain_RAW_Files&amp;diff=1170089"/>
		<updated>2012-07-02T18:48:58Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: /* LLRAW fidelity */ tweaky tweaky&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LLRAW fidelity ==&lt;br /&gt;
&lt;br /&gt;
While tinkering with LLRAW export code, I decided to plot a graph of the values one can fit into Linden Lab&#039;s 13 channel RAW terrain format.&lt;br /&gt;
&lt;br /&gt;
[[File:Graph-of-possible-terrain-values.png|1024px|thumb|image is rather wide :P]]&lt;br /&gt;
&lt;br /&gt;
* y-axis is the altitude of a point on the terrain&lt;br /&gt;
* first non-zero value is 0.0078125&lt;br /&gt;
* excluding non-zero values, the number of unique values is 17577 (non-zero sans uniqueness would be 255x255)&lt;br /&gt;
* unless a green value of 255 is hardcoded to a divisor of 2, the highest value is 508.0078125 &amp;lt;math&amp;gt;255/(255/128)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[User:SignpostMarv Martin|SignpostMarv Martin]] 11:44, 2 July 2012 (PDT)&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:Tips_for_Creating_Heightfields_and_Details_on_Terrain_RAW_Files&amp;diff=1170088</id>
		<title>Talk:Tips for Creating Heightfields and Details on Terrain RAW Files</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:Tips_for_Creating_Heightfields_and_Details_on_Terrain_RAW_Files&amp;diff=1170088"/>
		<updated>2012-07-02T18:44:21Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: /* LLRAW fidelity */ bork&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LLRAW fidelity ==&lt;br /&gt;
&lt;br /&gt;
While tinkering with LLRAW export code, I decided to plot a graph of the values one can fit into Linden Lab&#039;s 13 channel RAW terrain format.&lt;br /&gt;
[[File:Graph-of-possible-terrain-values.png]]&lt;br /&gt;
&lt;br /&gt;
* y-axis is the altitude of a point on the terrain&lt;br /&gt;
* first non-zero value is 0.0078125&lt;br /&gt;
* excluding non-zero values, the number of unique values is 17577 (non-zero sans uniqueness would be 255x255)&lt;br /&gt;
* unless a green value of 255 is hardcoded to a divisor of 2, the highest value is 508.0078125 &amp;lt;math&amp;gt;255/(255/128)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[User:SignpostMarv Martin|SignpostMarv Martin]] 11:44, 2 July 2012 (PDT)&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:Tips_for_Creating_Heightfields_and_Details_on_Terrain_RAW_Files&amp;diff=1170087</id>
		<title>Talk:Tips for Creating Heightfields and Details on Terrain RAW Files</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:Tips_for_Creating_Heightfields_and_Details_on_Terrain_RAW_Files&amp;diff=1170087"/>
		<updated>2012-07-02T18:44:03Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: LLRAW fidelity&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== LLRAW fidelity ==&lt;br /&gt;
&lt;br /&gt;
While tinkering with LLRAW export code, I decided to plot a graph of the values one can fit into Linden Lab&#039;s 13 channel RAW terrain format.&lt;br /&gt;
[[File:File:Graph-of-possible-terrain-values.png]]&lt;br /&gt;
&lt;br /&gt;
* y-axis is the altitude of a point on the terrain&lt;br /&gt;
* first non-zero value is 0.0078125&lt;br /&gt;
* excluding non-zero values, the number of unique values is 17577 (non-zero sans uniqueness would be 255x255)&lt;br /&gt;
* unless a green value of 255 is hardcoded to a divisor of 2, the highest value is 508.0078125 &amp;lt;math&amp;gt;255/(255/128)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[User:SignpostMarv Martin|SignpostMarv Martin]] 11:44, 2 July 2012 (PDT)&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=File:Graph-of-possible-terrain-values.png&amp;diff=1170085</id>
		<title>File:Graph-of-possible-terrain-values.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=File:Graph-of-possible-terrain-values.png&amp;diff=1170085"/>
		<updated>2012-07-02T18:37:56Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: graph of unique values that&amp;#039;re possible to be represented in LLRAW&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;graph of unique values that&#039;re possible to be represented in LLRAW&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Linden_Lab_Official_talk:Map_API_Reference&amp;diff=1169658</id>
		<title>Linden Lab Official talk:Map API Reference</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Linden_Lab_Official_talk:Map_API_Reference&amp;diff=1169658"/>
		<updated>2012-06-23T00:48:27Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: Outdated documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Outdated documentation ==&lt;br /&gt;
&lt;br /&gt;
As noted [https://jira.secondlife.com/browse/WEB-4799?focusedCommentId=331814&amp;amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-331814 in my jira comment], the documentation for the map api is outdated.&lt;br /&gt;
&lt;br /&gt;
[[User:SignpostMarv Martin|SignpostMarv Martin]] 17:48, 22 June 2012 (PDT)&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/exec.lsl&amp;diff=1165380</id>
		<title>User:SignpostMarv Martin/exec.lsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/exec.lsl&amp;diff=1165380"/>
		<updated>2012-04-10T00:01:42Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: moving stuff inside comment header&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;/**&lt;br /&gt;
*   @author SignpostMarv Martin&lt;br /&gt;
*   @copyright SignpostMarv Martin 2007-09-17 16:19:09&lt;br /&gt;
*   @brief Executes arbitrary LSL commands as from string input. This script was originally written 2007-09-17. It&#039;s old, not entirely graceful and was only done as an experiment.&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
list valid_commands = [&lt;br /&gt;
&amp;quot;llOwnerSay&amp;quot;,&lt;br /&gt;
&amp;quot;llInstantMessage&amp;quot;,&lt;br /&gt;
&amp;quot;llWhisper&amp;quot;,&lt;br /&gt;
&amp;quot;llSay&amp;quot;,&lt;br /&gt;
&amp;quot;llShout&amp;quot;,&lt;br /&gt;
&amp;quot;llRegionSay&amp;quot;,&lt;br /&gt;
&amp;quot;llDialog&amp;quot;&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
string identify_command(string input)&lt;br /&gt;
{&lt;br /&gt;
    integer loc = llSubStringIndex(input,&amp;quot;:&amp;quot;);&lt;br /&gt;
    if(loc == -1)&lt;br /&gt;
    {&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        loc = llListFindList(valid_commands,[llGetSubString(input,0,loc - 1)]);&lt;br /&gt;
        if(loc == -1)&lt;br /&gt;
        {&lt;br /&gt;
            return &amp;quot;&amp;quot;;   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            return llList2String(valid_commands,loc);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
execute_command(string command,string data)&lt;br /&gt;
{&lt;br /&gt;
    list foo = llCSV2List(data);&lt;br /&gt;
    if(command == &amp;quot;llOwnerSay&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        foo = [];&lt;br /&gt;
        llOwnerSay(data);&lt;br /&gt;
    }&lt;br /&gt;
    else if(command == &amp;quot;llInstantMessage&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        llInstantMessage((key)llList2String(foo,0),llList2CSV(llList2List(foo,1,-1)));&lt;br /&gt;
    }&lt;br /&gt;
    else if(command == &amp;quot;llDialog&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        llDialog(   (key)llList2String(foo,0),&lt;br /&gt;
                    llList2String(foo,1),&lt;br /&gt;
                    llList2List(foo,3,-1),&lt;br /&gt;
                    (integer)llList2String(foo,2)&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
    else if(command == &amp;quot;llWhisper&amp;quot; || command == &amp;quot;llSay&amp;quot; || command == &amp;quot;llShout&amp;quot; || command == &amp;quot;llRegionSay&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        integer bar = (integer)llList2String(foo,0);&lt;br /&gt;
        data = llList2CSV(llList2List(foo,1,-1));&lt;br /&gt;
        if(command == &amp;quot;llWhisper&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llWhisper(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
        else if(command == &amp;quot;llSay&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llSay(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
        else if(command == &amp;quot;llShout&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llShout(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
        else if(command == &amp;quot;llRegionSay&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llRegionSay(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
string _data(string payload)&lt;br /&gt;
{&lt;br /&gt;
    return llGetSubString(payload,llSubStringIndex(payload,&amp;quot;:&amp;quot;) + 1,-1);&lt;br /&gt;
}&lt;br /&gt;
process_payload(string payload,key is_for)&lt;br /&gt;
{&lt;br /&gt;
    string command = identify_command(payload);&lt;br /&gt;
    if(command == &amp;quot;&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        llInstantMessage(is_for,&amp;quot;/me recieved invalid payload&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        execute_command(command,_data(payload));&lt;br /&gt;
    }&lt;br /&gt;
    llOwnerSay((string)llGetFreeMemory());&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 test=&amp;quot;llWhisper:0,&amp;quot; + (string)llGetOwner() + &amp;quot;,;;faoskf;aoskdfasd,,,, f;asdfoka;eofk&amp;quot;;&lt;br /&gt;
        process_payload(test,llGetOwner());&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/exec.lsl&amp;diff=1165379</id>
		<title>User:SignpostMarv Martin/exec.lsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/exec.lsl&amp;diff=1165379"/>
		<updated>2012-04-09T23:59:05Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: adding author header&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This script was originally written 2007-09-17 10:46:16. It&#039;s old, not entirely graceful and was only done as an experiment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;/**&lt;br /&gt;
*   @author SignpostMarv Martin&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
list valid_commands = [&lt;br /&gt;
&amp;quot;llOwnerSay&amp;quot;,&lt;br /&gt;
&amp;quot;llInstantMessage&amp;quot;,&lt;br /&gt;
&amp;quot;llWhisper&amp;quot;,&lt;br /&gt;
&amp;quot;llSay&amp;quot;,&lt;br /&gt;
&amp;quot;llShout&amp;quot;,&lt;br /&gt;
&amp;quot;llRegionSay&amp;quot;,&lt;br /&gt;
&amp;quot;llDialog&amp;quot;&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
string identify_command(string input)&lt;br /&gt;
{&lt;br /&gt;
    integer loc = llSubStringIndex(input,&amp;quot;:&amp;quot;);&lt;br /&gt;
    if(loc == -1)&lt;br /&gt;
    {&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        loc = llListFindList(valid_commands,[llGetSubString(input,0,loc - 1)]);&lt;br /&gt;
        if(loc == -1)&lt;br /&gt;
        {&lt;br /&gt;
            return &amp;quot;&amp;quot;;   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            return llList2String(valid_commands,loc);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
execute_command(string command,string data)&lt;br /&gt;
{&lt;br /&gt;
    list foo = llCSV2List(data);&lt;br /&gt;
    if(command == &amp;quot;llOwnerSay&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        foo = [];&lt;br /&gt;
        llOwnerSay(data);&lt;br /&gt;
    }&lt;br /&gt;
    else if(command == &amp;quot;llInstantMessage&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        llInstantMessage((key)llList2String(foo,0),llList2CSV(llList2List(foo,1,-1)));&lt;br /&gt;
    }&lt;br /&gt;
    else if(command == &amp;quot;llDialog&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        llDialog(   (key)llList2String(foo,0),&lt;br /&gt;
                    llList2String(foo,1),&lt;br /&gt;
                    llList2List(foo,3,-1),&lt;br /&gt;
                    (integer)llList2String(foo,2)&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
    else if(command == &amp;quot;llWhisper&amp;quot; || command == &amp;quot;llSay&amp;quot; || command == &amp;quot;llShout&amp;quot; || command == &amp;quot;llRegionSay&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        integer bar = (integer)llList2String(foo,0);&lt;br /&gt;
        data = llList2CSV(llList2List(foo,1,-1));&lt;br /&gt;
        if(command == &amp;quot;llWhisper&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llWhisper(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
        else if(command == &amp;quot;llSay&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llSay(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
        else if(command == &amp;quot;llShout&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llShout(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
        else if(command == &amp;quot;llRegionSay&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llRegionSay(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
string _data(string payload)&lt;br /&gt;
{&lt;br /&gt;
    return llGetSubString(payload,llSubStringIndex(payload,&amp;quot;:&amp;quot;) + 1,-1);&lt;br /&gt;
}&lt;br /&gt;
process_payload(string payload,key is_for)&lt;br /&gt;
{&lt;br /&gt;
    string command = identify_command(payload);&lt;br /&gt;
    if(command == &amp;quot;&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        llInstantMessage(is_for,&amp;quot;/me recieved invalid payload&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        execute_command(command,_data(payload));&lt;br /&gt;
    }&lt;br /&gt;
    llOwnerSay((string)llGetFreeMemory());&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 test=&amp;quot;llWhisper:0,&amp;quot; + (string)llGetOwner() + &amp;quot;,;;faoskf;aoskdfasd,,,, f;asdfoka;eofk&amp;quot;;&lt;br /&gt;
        process_payload(test,llGetOwner());&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/exec.lsl&amp;diff=1165378</id>
		<title>User:SignpostMarv Martin/exec.lsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/exec.lsl&amp;diff=1165378"/>
		<updated>2012-04-09T23:58:00Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: dumping a 5 year old LSL script that I wrote for giggles.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This script was originally written 2007-09-17 10:46:16. It&#039;s old, not entirely graceful and was only done as an experiment.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;list valid_commands = [&lt;br /&gt;
&amp;quot;llOwnerSay&amp;quot;,&lt;br /&gt;
&amp;quot;llInstantMessage&amp;quot;,&lt;br /&gt;
&amp;quot;llWhisper&amp;quot;,&lt;br /&gt;
&amp;quot;llSay&amp;quot;,&lt;br /&gt;
&amp;quot;llShout&amp;quot;,&lt;br /&gt;
&amp;quot;llRegionSay&amp;quot;,&lt;br /&gt;
&amp;quot;llDialog&amp;quot;&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
string identify_command(string input)&lt;br /&gt;
{&lt;br /&gt;
    integer loc = llSubStringIndex(input,&amp;quot;:&amp;quot;);&lt;br /&gt;
    if(loc == -1)&lt;br /&gt;
    {&lt;br /&gt;
        return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        loc = llListFindList(valid_commands,[llGetSubString(input,0,loc - 1)]);&lt;br /&gt;
        if(loc == -1)&lt;br /&gt;
        {&lt;br /&gt;
            return &amp;quot;&amp;quot;;   &lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            return llList2String(valid_commands,loc);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
execute_command(string command,string data)&lt;br /&gt;
{&lt;br /&gt;
    list foo = llCSV2List(data);&lt;br /&gt;
    if(command == &amp;quot;llOwnerSay&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        foo = [];&lt;br /&gt;
        llOwnerSay(data);&lt;br /&gt;
    }&lt;br /&gt;
    else if(command == &amp;quot;llInstantMessage&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        llInstantMessage((key)llList2String(foo,0),llList2CSV(llList2List(foo,1,-1)));&lt;br /&gt;
    }&lt;br /&gt;
    else if(command == &amp;quot;llDialog&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        llDialog(   (key)llList2String(foo,0),&lt;br /&gt;
                    llList2String(foo,1),&lt;br /&gt;
                    llList2List(foo,3,-1),&lt;br /&gt;
                    (integer)llList2String(foo,2)&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
    else if(command == &amp;quot;llWhisper&amp;quot; || command == &amp;quot;llSay&amp;quot; || command == &amp;quot;llShout&amp;quot; || command == &amp;quot;llRegionSay&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        integer bar = (integer)llList2String(foo,0);&lt;br /&gt;
        data = llList2CSV(llList2List(foo,1,-1));&lt;br /&gt;
        if(command == &amp;quot;llWhisper&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llWhisper(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
        else if(command == &amp;quot;llSay&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llSay(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
        else if(command == &amp;quot;llShout&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llShout(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
        else if(command == &amp;quot;llRegionSay&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            llRegionSay(bar,data);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
string _data(string payload)&lt;br /&gt;
{&lt;br /&gt;
    return llGetSubString(payload,llSubStringIndex(payload,&amp;quot;:&amp;quot;) + 1,-1);&lt;br /&gt;
}&lt;br /&gt;
process_payload(string payload,key is_for)&lt;br /&gt;
{&lt;br /&gt;
    string command = identify_command(payload);&lt;br /&gt;
    if(command == &amp;quot;&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        llInstantMessage(is_for,&amp;quot;/me recieved invalid payload&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        execute_command(command,_data(payload));&lt;br /&gt;
    }&lt;br /&gt;
    llOwnerSay((string)llGetFreeMemory());&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 test=&amp;quot;llWhisper:0,&amp;quot; + (string)llGetOwner() + &amp;quot;,;;faoskf;aoskdfasd,,,, f;asdfoka;eofk&amp;quot;;&lt;br /&gt;
        process_payload(test,llGetOwner());&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Frame_Labels&amp;diff=1159640</id>
		<title>Open Prim Animator/Frame Labels</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Frame_Labels&amp;diff=1159640"/>
		<updated>2011-12-14T20:10:59Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
//!  @brief Provides an API to allow animation frames to be &amp;quot;labelled&amp;quot; so they can be called by string instead of integer.&lt;br /&gt;
/**&lt;br /&gt;
*    @author SignpostMarv Martin&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
getRecordedSnapshots(){ // short-hand for getting the number of animation frames&lt;br /&gt;
    llMessageLinked(LINK_THIS,-1,&amp;quot;XDrecordedSnapshots&amp;quot;,NULL_KEY);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//!  name of the notecard to load the frame labels from. Each label should be on a new line corresponding to the animation frame (first line first frame, second line second frame and so on)&lt;br /&gt;
string notecard = &amp;quot;OPA-Frame-Labels&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  notecard contents&lt;br /&gt;
string contents;&lt;br /&gt;
&lt;br /&gt;
//!  notecard lines&lt;br /&gt;
list   _contents;&lt;br /&gt;
&lt;br /&gt;
//!  dataserver keys for non-sequential loading of notecard lines.&lt;br /&gt;
list multithread_fetch = [];&lt;br /&gt;
&lt;br /&gt;
//!  dataserver key for fetching the number of notecard lines&lt;br /&gt;
key nlq;&lt;br /&gt;
&lt;br /&gt;
//!  Yet another vestigial copypasta.&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s=1000;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(_export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//!  number of animation frames&lt;br /&gt;
integer recordedSnapshots = 0;&lt;br /&gt;
&lt;br /&gt;
//!  command to change the current animation frame.&lt;br /&gt;
key op_change_frame = &amp;quot;1071f377-8623-4ed3-acc1-d30cabb4524a&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer type = llGetInventoryType(notecard); // check the notecard is in inventory&lt;br /&gt;
        if(type == INVENTORY_NONE){ // if type is INVENTORY_NONE it isn&#039;t there.&lt;br /&gt;
            llOwnerSay(&amp;quot;Notecard not found&amp;quot;);&lt;br /&gt;
        }else if(type != INVENTORY_NOTECARD){ // if type is not INVENTORY_NOTECARD, something else is hogging the name.&lt;br /&gt;
            llOwnerSay(&amp;quot;Inventory item found with name of notecard, but it is not a notecard&amp;quot;);&lt;br /&gt;
        }else{ // notecard found, proceeding with parsing process&lt;br /&gt;
            state num_lines;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){ // rather than resetting the script, we jump straight to the num_lines state if the notecard is now found.&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY &amp;amp;&amp;amp; llGetInventoryType(notecard) == INVENTORY_NOTECARD){&lt;br /&gt;
            state num_lines;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//    state_exit(){&lt;br /&gt;
//        llOwnerSay(&amp;quot;Notecard found, parsing&amp;quot;);&lt;br /&gt;
//    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state num_lines{ // we&#039;re using separate states to avoid race conditions with changed inventory etc.&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        nlq = llGetNumberOfNotecardLines(notecard); // fire off a request for the notecard lines&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        if(q == nlq){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j = (integer)m;&lt;br /&gt;
            if(j &amp;lt; 1){&lt;br /&gt;
                contents = &amp;quot;&amp;quot;;&lt;br /&gt;
                state done_reading;&lt;br /&gt;
            }&lt;br /&gt;
            list    k = []; // declaring list k = []; isn&#039;t exactly necessary, you could do list k;&lt;br /&gt;
            list    l = [];&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){ // since we don&#039;t have the concept of transactions in LSL scripts, we&#039;re going to build up these lists separately &lt;br /&gt;
                k += [NULL_KEY];&lt;br /&gt;
                l += [NULL_KEY];&lt;br /&gt;
            }&lt;br /&gt;
            _contents = k; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            multithread_fetch = l; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            k = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            l = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            state mtf;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state mtf{ // fetch all notecard lines without the delay caused by traditional sequential loading.&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer i;&lt;br /&gt;
        integer j=llGetListLength(multithread_fetch);&lt;br /&gt;
        for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
            multithread_fetch = llListReplaceList(multithread_fetch,[llGetNotecardLine(notecard,i)],i,i); // sets the notecard fetching away&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        integer i = llListFindList(multithread_fetch,[q]);&lt;br /&gt;
        if(i &amp;gt;= 0){&lt;br /&gt;
            _contents = llListReplaceList(_contents,[m],i,i); // the traditional method of notecard fetching in LSL is single-threaded, getting one line at a time&lt;br /&gt;
        }&lt;br /&gt;
        if(llListFindList(_contents,[NULL_KEY]) == -1){ // since we started out with a NULLL_KEY-filled list, if there aren&#039;t any NUL_KEY in the list then we know it&#039;s done. caveat scriptor: since key and string types are interchangeable &lt;br /&gt;
            contents = llDumpList2String(_contents,&amp;quot;\n&amp;quot;);&lt;br /&gt;
            state done_reading;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state_exit(){&lt;br /&gt;
        _contents = [];&lt;br /&gt;
        multithread_fetch = [];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state done_reading{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        _contents = llParseString2List(contents, [&amp;quot;\n&amp;quot;],[]);&lt;br /&gt;
//        llOwnerSay((string)llGetListLength(_contents) + &amp;quot; frame labels found&amp;quot;);&lt;br /&gt;
        getRecordedSnapshots();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer s, integer n, string m, key i){&lt;br /&gt;
        if(m == &amp;quot;XDrecordedSnapshots&amp;quot; &amp;amp;&amp;amp; n &amp;gt;= 0){ // if we&#039;re updating the number of animation frames&lt;br /&gt;
            recordedSnapshots = n;&lt;br /&gt;
            if(recordedSnapshots == 1){ // and there&#039;s only one frame&lt;br /&gt;
                llMessageLinked(LINK_THIS,0,&amp;quot;XDplay&amp;quot;,NULL_KEY); // play it.&lt;br /&gt;
            }&lt;br /&gt;
        }else if(i == op_change_frame){ // if we receive a command to change to an animation frame by a named label,&lt;br /&gt;
            integer frame = llListFindList(_contents,[m]); // check the label exists in the notecard contents&lt;br /&gt;
            if(frame &amp;gt;= 0){ // then if the named label does exist,&lt;br /&gt;
                llMessageLinked(LINK_THIS,frame + 1,&amp;quot;XDshow&amp;quot;,NULL_KEY); // show it.&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_INVENTORY){&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
[[Category:Open Prim Animator|Frame Labels]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Frame_Labels&amp;diff=1159613</id>
		<title>Open Prim Animator/Frame Labels</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Frame_Labels&amp;diff=1159613"/>
		<updated>2011-12-14T13:40:27Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
//!  @brief Provides an API to allow animation frames to be &amp;quot;labelled&amp;quot; so they can be called by string instead of integer.&lt;br /&gt;
/**&lt;br /&gt;
*    @author SignpostMarv Martin&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
getRecordedSnapshots(){ // short-hand for getting the number of animation frames&lt;br /&gt;
    llMessageLinked(LINK_THIS,-1,&amp;quot;XDrecordedSnapshots&amp;quot;,NULL_KEY);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//!  name of the notecard to load the frame labels from. Each label should be on a new line corresponding to the animation frame (first line first frame, second line second frame and so on)&lt;br /&gt;
string notecard = &amp;quot;OPA-Frame-Labels&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  notecard contents&lt;br /&gt;
string contents;&lt;br /&gt;
&lt;br /&gt;
//!  notecard lines&lt;br /&gt;
list   _contents;&lt;br /&gt;
&lt;br /&gt;
//!  dataserver keys for non-sequential loading of notecard lines.&lt;br /&gt;
list multithread_fetch = [];&lt;br /&gt;
&lt;br /&gt;
//!  dataserver key for fetching the number of notecard lines&lt;br /&gt;
key nlq;&lt;br /&gt;
&lt;br /&gt;
//!  Yet another vestigial copypasta.&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s=1000;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(_export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//!  number of animation frames&lt;br /&gt;
integer recordedSnapshots = 0;&lt;br /&gt;
&lt;br /&gt;
//!  command to change the current animation frame.&lt;br /&gt;
key op_change_frame = &amp;quot;1071f377-8623-4ed3-acc1-d30cabb4524a&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer type = llGetInventoryType(notecard); // check the notecard is in inventory&lt;br /&gt;
        if(type == INVENTORY_NONE){ // if type is INVENTORY_NONE it isn&#039;t there.&lt;br /&gt;
            llOwnerSay(&amp;quot;Notecard not found&amp;quot;);&lt;br /&gt;
        }else if(type != INVENTORY_NOTECARD){ // if type is not INVENTORY_NOTECARD, something else is hogging the name.&lt;br /&gt;
            llOwnerSay(&amp;quot;Inventory item found with name of notecard, but it is not a notecard&amp;quot;);&lt;br /&gt;
        }else{ // notecard found, proceeding with parsing process&lt;br /&gt;
            state num_lines;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){ // rather than resetting the script, we jump straight to the num_lines state if the notecard is now found.&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY &amp;amp;&amp;amp; llGetInventoryType(notecard) == INVENTORY_NOTECARD){&lt;br /&gt;
            state num_lines;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
//    state_exit(){&lt;br /&gt;
//        llOwnerSay(&amp;quot;Notecard found, parsing&amp;quot;);&lt;br /&gt;
//    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state num_lines{ // we&#039;re using separate states to avoid race conditions with changed inventory etc.&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        nlq = llGetNumberOfNotecardLines(notecard); // fire off a request for the notecard lines&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        if(q == nlq){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j = (integer)m;&lt;br /&gt;
            if(j &amp;lt; 1){&lt;br /&gt;
                contents = &amp;quot;&amp;quot;;&lt;br /&gt;
                state done_reading;&lt;br /&gt;
            }&lt;br /&gt;
            list    k = []; // declaring list k = []; isn&#039;t exactly necessary, you could do list k;&lt;br /&gt;
            list    l = [];&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){ // since we don&#039;t have the concept of transactions in LSL scripts, we&#039;re going to build up these lists separately &lt;br /&gt;
                k += [NULL_KEY];&lt;br /&gt;
                l += [NULL_KEY];&lt;br /&gt;
            }&lt;br /&gt;
            _contents = k; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            multithread_fetch = l; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            k = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            l = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            state mtf;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state mtf{ // fetch all notecard lines without the delay caused by traditional sequential loading.&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer i;&lt;br /&gt;
        integer j=llGetListLength(multithread_fetch);&lt;br /&gt;
        for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
            multithread_fetch = llListReplaceList(multithread_fetch,[llGetNotecardLine(notecard,i)],i,i); // sets the notecard fetching away&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        integer i = llListFindList(multithread_fetch,[q]);&lt;br /&gt;
        if(i &amp;gt;= 0){&lt;br /&gt;
            _contents = llListReplaceList(_contents,[m],i,i); // the traditional method of notecard fetching in LSL is single-threaded, getting one line at a time&lt;br /&gt;
        }&lt;br /&gt;
        if(llListFindList(_contents,[NULL_KEY]) == -1){ // since we started out with a NULLL_KEY-filled list, if there aren&#039;t any NUL_KEY in the list then we know it&#039;s done. caveat scriptor: since key and string types are interchangeable &lt;br /&gt;
            contents = llDumpList2String(_contents,&amp;quot;\n&amp;quot;);&lt;br /&gt;
            state done_reading;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state_exit(){&lt;br /&gt;
        _contents = [];&lt;br /&gt;
        multithread_fetch = [];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state done_reading{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        _contents = llParseString2List(contents, [&amp;quot;\n&amp;quot;],[]);&lt;br /&gt;
//        llOwnerSay((string)llGetListLength(_contents) + &amp;quot; frame labels found&amp;quot;);&lt;br /&gt;
        getRecordedSnapshots();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer s, integer n, string m, key i){&lt;br /&gt;
        if(m == &amp;quot;XDrecordedSnapshots&amp;quot; &amp;amp;&amp;amp; n &amp;gt;= 0){ // if we&#039;re updating the number of animation frames&lt;br /&gt;
            recordedSnapshots = n;&lt;br /&gt;
            if(recordedSnapshots == 1){ // and there&#039;s only one frame&lt;br /&gt;
                llMessageLinked(LINK_THIS,0,&amp;quot;XDplay&amp;quot;,NULL_KEY); // play it.&lt;br /&gt;
            }&lt;br /&gt;
        }else if(i == op_change_frame){ // if we receive a command to change to an animation frame by a named label,&lt;br /&gt;
            integer frame = llListFindList(_contents,[m]); // check the label exists in the notecard contents&lt;br /&gt;
            if(frame &amp;gt;= 0){ // then if the named label does exist,&lt;br /&gt;
                llMessageLinked(LINK_THIS,frame + 1,&amp;quot;XDshow&amp;quot;,NULL_KEY); // show it.&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_INVENTORY){&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
[[Category:Open Prim Animatior|Frame Labels]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Frame_Labels&amp;diff=1159612</id>
		<title>Open Prim Animator/Frame Labels</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Frame_Labels&amp;diff=1159612"/>
		<updated>2011-12-14T13:18:24Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: Committing changes made to OPA made over the past year at work&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
getRecordedSnapshots(){&lt;br /&gt;
    llMessageLinked(LINK_THIS,-1,&amp;quot;XDrecordedSnapshots&amp;quot;,NULL_KEY);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string notecard = &amp;quot;OPA-Frame-Labels&amp;quot;;&lt;br /&gt;
string contents;&lt;br /&gt;
list   _contents;&lt;br /&gt;
list multithread_fetch = [];&lt;br /&gt;
key nlq;&lt;br /&gt;
&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s=1000;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(_export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer recordedSnapshots = 0;&lt;br /&gt;
key op_change_frame = &amp;quot;1071f377-8623-4ed3-acc1-d30cabb4524a&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer type = llGetInventoryType(notecard);&lt;br /&gt;
        if(type == INVENTORY_NONE){&lt;br /&gt;
            llOwnerSay(&amp;quot;Notecard not found&amp;quot;);&lt;br /&gt;
        }else if(type != INVENTORY_NOTECARD){&lt;br /&gt;
            llOwnerSay(&amp;quot;Inventory item found with name of notecard, but it is not a notecard&amp;quot;);&lt;br /&gt;
        }else{&lt;br /&gt;
            state num_lines;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY &amp;amp;&amp;amp; llGetInventoryType(notecard) == INVENTORY_NOTECARD){&lt;br /&gt;
            state num_lines;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state_exit(){&lt;br /&gt;
//        llOwnerSay(&amp;quot;Notecard found, parsing&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state num_lines{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        nlq = llGetNumberOfNotecardLines(notecard);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        if(q == nlq){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j = (integer)m;&lt;br /&gt;
            if(j &amp;lt; 1){&lt;br /&gt;
                contents = &amp;quot;&amp;quot;;&lt;br /&gt;
                state done_reading;&lt;br /&gt;
            }&lt;br /&gt;
            list    k = []; // declaring list k = []; isn&#039;t exactly necessary, you could do list k;&lt;br /&gt;
            list    l = [];&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){ // since we don&#039;t have the concept of transactions in LSL scripts, we&#039;re going to build up these lists separately &lt;br /&gt;
                k += [NULL_KEY];&lt;br /&gt;
                l += [NULL_KEY];&lt;br /&gt;
            }&lt;br /&gt;
            _contents = k; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            multithread_fetch = l; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            k = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            l = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            state mtf;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state mtf{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer i;&lt;br /&gt;
        integer j=llGetListLength(multithread_fetch);&lt;br /&gt;
        for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
            multithread_fetch = llListReplaceList(multithread_fetch,[llGetNotecardLine(notecard,i)],i,i); // sets the notecard fetching away&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        integer i = llListFindList(multithread_fetch,[q]);&lt;br /&gt;
        if(i &amp;gt;= 0){&lt;br /&gt;
            _contents = llListReplaceList(_contents,[m],i,i); // the traditional method of notecard fetching in LSL is single-threaded, getting one line at a time&lt;br /&gt;
        }&lt;br /&gt;
        if(llListFindList(_contents,[NULL_KEY]) == -1){ // since we started out with a NULLL_KEY-filled list, if there aren&#039;t any NUL_KEY in the list then we know it&#039;s done. caveat scriptor: since key and string types are interchangeable &lt;br /&gt;
            contents = llDumpList2String(_contents,&amp;quot;\n&amp;quot;);&lt;br /&gt;
            state done_reading;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state_exit(){&lt;br /&gt;
        _contents = [];&lt;br /&gt;
        multithread_fetch = [];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state done_reading{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        _contents = llParseString2List(contents, [&amp;quot;\n&amp;quot;],[]);&lt;br /&gt;
//        llOwnerSay((string)llGetListLength(_contents) + &amp;quot; frame labels found&amp;quot;);&lt;br /&gt;
        getRecordedSnapshots();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer s, integer n, string m, key i){&lt;br /&gt;
        if(m == &amp;quot;XDrecordedSnapshots&amp;quot; &amp;amp;&amp;amp; n &amp;gt;= 0){&lt;br /&gt;
            recordedSnapshots = n;&lt;br /&gt;
            if(recordedSnapshots == 1){&lt;br /&gt;
                llMessageLinked(LINK_THIS,0,&amp;quot;XDplay&amp;quot;,NULL_KEY);&lt;br /&gt;
            }&lt;br /&gt;
        }else if(i == op_change_frame){&lt;br /&gt;
            integer frame = llListFindList(_contents,[m]);&lt;br /&gt;
            if(frame &amp;gt;= 0){&lt;br /&gt;
                llMessageLinked(LINK_THIS,frame + 1,&amp;quot;XDshow&amp;quot;,NULL_KEY);&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_INVENTORY){&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
[[Category:Open Prim Animatior|Frame Labels]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Touch_Ping_Pong&amp;diff=1159611</id>
		<title>Open Prim Animator/Touch Ping Pong</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Touch_Ping_Pong&amp;diff=1159611"/>
		<updated>2011-12-14T13:04:45Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: moar documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
//!  @brief This is a utility script for OPA for cases when animation frames are meant to be viewed sequentially in both forward and &amp;quot;reverse&amp;quot;.&lt;br /&gt;
/**&lt;br /&gt;
*    @author SignpostMarv Martin&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
//!  The number of animation frames&lt;br /&gt;
integer count;&lt;br /&gt;
&lt;br /&gt;
//!  if TRUE then the &amp;quot;ping pong&amp;quot; is in effect and should not be interupted.&lt;br /&gt;
integer running=FALSE;&lt;br /&gt;
&lt;br /&gt;
//!  interval between animation frames&lt;br /&gt;
float interval = 1.0;&lt;br /&gt;
&lt;br /&gt;
//!  &lt;br /&gt;
integer at=1;&lt;br /&gt;
integer mod=1;&lt;br /&gt;
default{&lt;br /&gt;
    state_entry() {&lt;br /&gt;
        llMessageLinked(LINK_ROOT, -1, &amp;quot;XDrecordedSnapshots&amp;quot;, NULL_KEY); // get the number of animation frames from the core OPA script.&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer s, integer n, string m, key i){&lt;br /&gt;
        if(m == &amp;quot;XDrecordedSnapshots&amp;quot; &amp;amp;&amp;amp; n &amp;gt;= 0){&lt;br /&gt;
            count = n; // update the number of animation frames&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    touch_start(integer t){&lt;br /&gt;
        if(!running){ // if we&#039;re not doing the &amp;quot;ping-pong&amp;quot;,&lt;br /&gt;
            running = TRUE; // set the flag to TRUE&lt;br /&gt;
            llSetTimerEvent(interval); // then set the timer event away.&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    timer(){&lt;br /&gt;
        if(count &amp;lt;= 0){&lt;br /&gt;
            llSetTimerEvent(0); // stop the timer&lt;br /&gt;
        }else{&lt;br /&gt;
            at += mod; // add the modifier (which may be a negative integer)&lt;br /&gt;
            if(at &amp;gt;= count){ // if we&#039;re at the end of the &amp;quot;ping-pong&amp;quot;, &lt;br /&gt;
                mod = -1; // change the mod to negative 1 in preparation of reversing the animation&lt;br /&gt;
                llSetTimerEvent(0); // turn off the timer&lt;br /&gt;
                running = FALSE; // set the running flag to FALSE so a user can touch the script.&lt;br /&gt;
            }else if(at &amp;lt;= 1){ // if we&#039;re at the end of the &amp;quot;pong-ping&amp;quot;,&lt;br /&gt;
                mod = 1; // change them od to positive one in preparation of running the animation&lt;br /&gt;
                llSetTimerEvent(0); // turn off the timer.&lt;br /&gt;
                running = FALSE; // set the running flag to FALSE so a user can touch the script.&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(LINK_ROOT, at, &amp;quot;XDshow&amp;quot;, NULL_KEY); // instruct the core OPA script to change the displayed animation frame.&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
[[Category:Open Prim Animator|Ping Pong]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Touch_Ping_Pong&amp;diff=1159610</id>
		<title>Open Prim Animator/Touch Ping Pong</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Touch_Ping_Pong&amp;diff=1159610"/>
		<updated>2011-12-14T12:47:28Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: Committing changes made to OPA made over the past year at work&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
integer count;&lt;br /&gt;
integer running=FALSE;&lt;br /&gt;
float interval = 1.0;&lt;br /&gt;
integer at=1;&lt;br /&gt;
integer mod=1;&lt;br /&gt;
default{&lt;br /&gt;
    state_entry() {&lt;br /&gt;
        llMessageLinked(LINK_ROOT, -1, &amp;quot;XDrecordedSnapshots&amp;quot;, NULL_KEY);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer s, integer n, string m, key i){&lt;br /&gt;
        if(m == &amp;quot;XDrecordedSnapshots&amp;quot; &amp;amp;&amp;amp; n &amp;gt;= 0){&lt;br /&gt;
            count = n;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    touch_start(integer t){&lt;br /&gt;
        if(!running){&lt;br /&gt;
            running = TRUE;&lt;br /&gt;
            llSetTimerEvent(interval);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    timer(){&lt;br /&gt;
        if(count &amp;lt;= 0){&lt;br /&gt;
            llSetTimerEvent(0);&lt;br /&gt;
        }else{&lt;br /&gt;
            at += mod;&lt;br /&gt;
            if(at &amp;gt;= count){&lt;br /&gt;
                mod = -1;&lt;br /&gt;
                llSetTimerEvent(0);&lt;br /&gt;
                running = FALSE;&lt;br /&gt;
            }else if(at &amp;lt;= 1){&lt;br /&gt;
                mod = 1;&lt;br /&gt;
                llSetTimerEvent(0);&lt;br /&gt;
                running = FALSE;&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(LINK_ROOT, at, &amp;quot;XDshow&amp;quot;, NULL_KEY);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
[[Category:Open Prim Animator|Ping Pong]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Notecard_Import&amp;diff=1159609</id>
		<title>Open Prim Animator/Notecard Import</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Notecard_Import&amp;diff=1159609"/>
		<updated>2011-12-14T12:42:11Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: moar documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
//!  @brief Imports a set of animation frames from a notecard&lt;br /&gt;
/**&lt;br /&gt;
*    @author SignpostMarv Martin&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
//!  name of notecard to parse&lt;br /&gt;
string notecard = &amp;quot;Open Prim Animator: Import&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  inventory key of notecard&lt;br /&gt;
key   _notecard;&lt;br /&gt;
&lt;br /&gt;
//!  Temporarily stores the entire notecard contents&lt;br /&gt;
string contents;&lt;br /&gt;
&lt;br /&gt;
//!  Since llGetNotecardLine() only reads the first 255 bytes of a notecard line, we need to temporarily store the notecard contents in a list before dumping it to the contents string.&lt;br /&gt;
list   _contents;&lt;br /&gt;
&lt;br /&gt;
//!  Whilst not truly multi-threaded, this script attempts non-sequential loading of the notecard (as opposed to sequential loading), theoretically providing some small performance gain&lt;br /&gt;
list multithread_fetch = [];&lt;br /&gt;
&lt;br /&gt;
//!  dataserver query variable used to determine how many lines are in a notecard- needed to pre-populate multithread_fetch to the correct size.&lt;br /&gt;
key nlq;&lt;br /&gt;
&lt;br /&gt;
//!  import command&lt;br /&gt;
key import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  export command&lt;br /&gt;
key export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  command for updating the root scale in the core OPA script&lt;br /&gt;
key op_alter_rootScale = &amp;quot;f9d3389e-a78c-43f8-9e35-c11adec112a5&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  command for restoring link order&lt;br /&gt;
key op_adjust_link_order_by_names = &amp;quot;e907917f-e5a3-490e-aaac-4596a0dc176d&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of link names&lt;br /&gt;
list names;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of animation frame positions&lt;br /&gt;
list pos;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of animation frame rotations&lt;br /&gt;
list rot;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of animation frame sizes&lt;br /&gt;
list size;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of root scale. This is needed in case a new animation was generated on an object with a different root scale to the prim the object the notecard is being imported to&lt;br /&gt;
vector rootScale;&lt;br /&gt;
&lt;br /&gt;
//!  I think this is here solely due to copypasta.&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s=1000;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(_export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        if(llGetInventoryType(notecard) == INVENTORY_NOTECARD){ // if the specified notecard is in the object,&lt;br /&gt;
            _notecard = llGetInventoryKey(notecard); // get the inventory key&lt;br /&gt;
            state num_lines; // then attempt to get the number of lines in the notecard&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY){ // if the inventory has changed (e.g. if the notecard *wasn&#039;t* in the object),&lt;br /&gt;
            llResetScript(); // restart the script&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state num_lines{ // there should probably be a CHANGED_INVENTORY check in case the scripts are running reaaaaallllyyyy slow.&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        nlq = llGetNumberOfNotecardLines(notecard); // attempt to get the number of lines in the notecard&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        if(q == nlq){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j = (integer)m;&lt;br /&gt;
            list    k = []; // declaring list k = []; isn&#039;t exactly necessary, you could do list k;&lt;br /&gt;
            list    l = [];&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){ // since we don&#039;t have the concept of transactions in LSL scripts, we&#039;re going to build up these lists separately &lt;br /&gt;
                k += [NULL_KEY];&lt;br /&gt;
                l += [NULL_KEY];&lt;br /&gt;
            }&lt;br /&gt;
            _contents = k; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            multithread_fetch = l; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            k = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            l = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            state mtf; // now we&#039;ve pre-populated the lists to the correct size, start the &amp;quot;multi-threaded fetch&amp;quot; of notecard contents.&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state mtf{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer i;&lt;br /&gt;
        integer j=llGetListLength(multithread_fetch); // see why we pre-populated it now ? :D&lt;br /&gt;
        for(i=0;i&amp;lt;j;++i){ // the reason we pre-populate rather than building the list here is to try and keep the level of consumed memory more consistent in this busy state, so the memory consumption doesn&#039;t steadily increase over time but regularly plateaus instead.&lt;br /&gt;
            multithread_fetch = llListReplaceList(multithread_fetch,[llGetNotecardLine(notecard,i)],i,i); // sets the notecard fetching away&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        integer i = llListFindList(multithread_fetch,[q]); // get the position of the dataserver query id &lt;br /&gt;
        if(i &amp;gt;= 0){&lt;br /&gt;
            _contents = llListReplaceList(_contents,[m],i,i); // the traditional method of notecard fetching in LSL is single-threaded, getting one line at a time&lt;br /&gt;
        }&lt;br /&gt;
        if(llListFindList(_contents,[NULL_KEY]) == -1){ // since we started out with a NULL_KEY-filled list, if there aren&#039;t any NULL_KEY in the list then we know it&#039;s done. caveat scriptor: since key and string types are interchangeable &lt;br /&gt;
            contents = llDumpList2String(_contents,&amp;quot;&amp;quot;);&lt;br /&gt;
            state done_reading;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state_exit(){ // do some cleanup in the event the LSL VM executing this script is silly.&lt;br /&gt;
        _contents = [];&lt;br /&gt;
        multithread_fetch = [];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state done_reading{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer rs_pos    = llSubStringIndex(contents,&amp;quot;rootscale:&amp;quot;); // get the string index for the rootscale block&lt;br /&gt;
        integer names_pos = llSubStringIndex(contents,&amp;quot;names:&amp;quot;); // get the string index for the names block&lt;br /&gt;
        integer pos_pos   = llSubStringIndex(contents,&amp;quot;pos:&amp;quot;); // get the string index for the position block&lt;br /&gt;
        integer rot_pos   = llSubStringIndex(contents,&amp;quot;rot:&amp;quot;); // get the string index for the rotation block&lt;br /&gt;
        integer size_pos  = llSubStringIndex(contents,&amp;quot;size:&amp;quot;); // get the string index for the size block&lt;br /&gt;
&lt;br /&gt;
        rootScale  = (vector)llGetSubString(contents, rs_pos + 10, names_pos - 1); // get the root scale from the notecard&lt;br /&gt;
        names      = llParseString2List(llGetSubString(contents,names_pos + 6,pos_pos - 1),[&amp;quot;|&amp;quot;],[]); // Fun Fact! Support for correcting link order was added in May 2011 but wasn&#039;t actually implemented until November 2011!&lt;br /&gt;
        pos        = llParseString2List(llGetSubString(contents,pos_pos + 4,rot_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        rot        = llParseString2List(llGetSubString(contents,rot_pos + 4,size_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        size       = llParseString2List(llGetSubString(contents,size_pos + 5,-1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
&lt;br /&gt;
        contents = &amp;quot;&amp;quot;; // clearing memory up, we don&#039;t need the string in memory now.&lt;br /&gt;
        integer a = llGetListLength(names);&lt;br /&gt;
        integer b = llGetListLength(pos);&lt;br /&gt;
        if(b % a || llGetListLength(rot) % a || llGetListLength(size) % a){ // since the number of names corresponds to the number of prims, we can use modulus to ensure that the notecard doesn&#039;t have a corrupt export.&lt;br /&gt;
            llOwnerSay(&amp;quot;List Lengths do not match, possible corrupted notecard (&amp;quot; + llList2CSV([a,llGetListLength(pos),llGetListLength(rot),llGetListLength(size)]) + &amp;quot;)&amp;quot;);&lt;br /&gt;
        }else{&lt;br /&gt;
            llMessageLinked(LINK_THIS,b,&amp;quot;XDimportLength&amp;quot;,NULL_KEY); // notecard contents are valid, core script can start import now.&lt;br /&gt;
            llOwnerSay(&amp;quot;Do import now&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY &amp;amp;&amp;amp; llGetInventoryKey(notecard) != _notecard){&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer s, integer n, string m, key k){&lt;br /&gt;
        if(m == &amp;quot;XDimportLength&amp;quot; &amp;amp;&amp;amp; n == -1){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j=llGetListLength(pos); // we&#039;ve already verified that pos, rot and size are of the appropriate length so we only need to get the length of one of these.&lt;br /&gt;
            integer l;&lt;br /&gt;
            integer namesLength=llGetListLength(names);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                l = llListFindList(names, [llGetLinkName(2 + (i % namesLength))]) + (llFloor(i / namesLength) * namesLength); // this is to fix any bugs caused by link order changes (finally added in November 2011)&lt;br /&gt;
                llMessageLinked(s,i,llDumpList2String([llList2Vector(pos,l),llList2Rot(rot,l),llList2Vector(size,l)],&amp;quot;|&amp;quot;),import); // send the import string to the core OPA script&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(s,0,(string)rootScale, op_alter_rootScale); // once we&#039;re done importing the position, rotation &amp;amp; size values for the animation frames, update the root scale to the value used in the creation of the animation frames.&lt;br /&gt;
            llOwnerSay(&amp;quot;Done importing&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    touch_start(integer t){&lt;br /&gt;
        llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
[[Category:Open Prim Animator|Notecard Import]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Notecard_Import&amp;diff=1159608</id>
		<title>Open Prim Animator/Notecard Import</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Notecard_Import&amp;diff=1159608"/>
		<updated>2011-12-14T12:41:24Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
//!  @brief Imports a set of animation frames from a notecard&lt;br /&gt;
/**&lt;br /&gt;
*    @author SignpostMarv Martin&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
//!  name of notecard to parse&lt;br /&gt;
string notecard = &amp;quot;Open Prim Animator: Import&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  inventory key of notecard&lt;br /&gt;
key   _notecard;&lt;br /&gt;
&lt;br /&gt;
//!  Temporarily stores the entire notecard contents&lt;br /&gt;
string contents;&lt;br /&gt;
&lt;br /&gt;
//!  Since llGetNotecardLine() only reads the first 255 bytes of a notecard line, we need to temporarily store the notecard contents in a list before dumping it to the contents string.&lt;br /&gt;
list   _contents;&lt;br /&gt;
&lt;br /&gt;
//!  Whilst not truly multi-threaded, this script attempts non-sequential loading of the notecard (as opposed to sequential loading), theoretically providing some small performance gain&lt;br /&gt;
list multithread_fetch = [];&lt;br /&gt;
&lt;br /&gt;
//!  dataserver query variable used to determine how many lines are in a notecard- needed to pre-populate multithread_fetch to the correct size.&lt;br /&gt;
key nlq;&lt;br /&gt;
&lt;br /&gt;
//!  import command&lt;br /&gt;
key import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  export command&lt;br /&gt;
key export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  command for updating the root scale in the core OPA script&lt;br /&gt;
key op_alter_rootScale = &amp;quot;f9d3389e-a78c-43f8-9e35-c11adec112a5&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  command for restoring link order&lt;br /&gt;
key op_adjust_link_order_by_names = &amp;quot;e907917f-e5a3-490e-aaac-4596a0dc176d&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of link names&lt;br /&gt;
list names;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of animation frame positions&lt;br /&gt;
list pos;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of animation frame rotations&lt;br /&gt;
list rot;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of animation frame sizes&lt;br /&gt;
list size;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of root scale. This is needed in case a new animation was generated on an object with a different root scale to the prim the object the notecard is being imported to&lt;br /&gt;
vector rootScale;&lt;br /&gt;
&lt;br /&gt;
//!  I think this is here solely due to copypasta.&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s=1000;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(_export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        if(llGetInventoryType(notecard) == INVENTORY_NOTECARD){ // if the specified notecard is in the object,&lt;br /&gt;
            _notecard = llGetInventoryKey(notecard); // get the inventory key&lt;br /&gt;
            state num_lines; // then attempt to get the number of lines in the notecard&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY){ // if the inventory has changed (e.g. if the notecard *wasn&#039;t* in the object),&lt;br /&gt;
            llResetScript(); // restart the script&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state num_lines{ // there should probably be a CHANGED_INVENTORY check in case the scripts are running reaaaaallllyyyy slow.&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        nlq = llGetNumberOfNotecardLines(notecard); // attempt to get the number of lines in the notecard&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        if(q == nlq){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j = (integer)m;&lt;br /&gt;
            list    k = []; // declaring list k = []; isn&#039;t exactly necessary, you could do list k;&lt;br /&gt;
            list    l = [];&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){ // since we don&#039;t have the concept of transactions in LSL scripts, we&#039;re going to build up these lists separately &lt;br /&gt;
                k += [NULL_KEY];&lt;br /&gt;
                l += [NULL_KEY];&lt;br /&gt;
            }&lt;br /&gt;
            _contents = k; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            multithread_fetch = l; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            k = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            l = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            state mtf; // now we&#039;ve pre-populated the lists to the correct size, start the &amp;quot;multi-threaded fetch&amp;quot; of notecard contents.&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state mtf{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer i;&lt;br /&gt;
        integer j=llGetListLength(multithread_fetch); // see why we pre-populated it now ? :D&lt;br /&gt;
        for(i=0;i&amp;lt;j;++i){ // the reason we pre-populate rather than building the list here is to try and keep the level of consumed memory more consistent in this busy state, so the memory consumption doesn&#039;t steadily increase over time but regularly plateaus instead.&lt;br /&gt;
            multithread_fetch = llListReplaceList(multithread_fetch,[llGetNotecardLine(notecard,i)],i,i); // sets the notecard fetching away&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        integer i = llListFindList(multithread_fetch,[q]); // get the position of the dataserver query id &lt;br /&gt;
        if(i &amp;gt;= 0){&lt;br /&gt;
            _contents = llListReplaceList(_contents,[m],i,i); // the traditional method of notecard fetching in LSL is single-threaded, getting one line at a time&lt;br /&gt;
        }&lt;br /&gt;
        if(llListFindList(_contents,[NULL_KEY]) == -1){ // since we started out with a NULL_KEY-filled list, if there aren&#039;t any NULL_KEY in the list then we know it&#039;s done. caveat scriptor: since key and string types are interchangeable &lt;br /&gt;
            contents = llDumpList2String(_contents,&amp;quot;&amp;quot;);&lt;br /&gt;
            state done_reading;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state_exit(){ // do some cleanup in the event the LSL VM executing this script is silly.&lt;br /&gt;
        _contents = [];&lt;br /&gt;
        multithread_fetch = [];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state done_reading{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer rs_pos    = llSubStringIndex(contents,&amp;quot;rootscale:&amp;quot;); // get the string index for the rootscale block&lt;br /&gt;
        integer names_pos = llSubStringIndex(contents,&amp;quot;names:&amp;quot;); // get the string index for the names block&lt;br /&gt;
        integer pos_pos   = llSubStringIndex(contents,&amp;quot;pos:&amp;quot;); // get the string index for the position block&lt;br /&gt;
        integer rot_pos   = llSubStringIndex(contents,&amp;quot;rot:&amp;quot;); // get the string index for the rotation block&lt;br /&gt;
        integer size_pos  = llSubStringIndex(contents,&amp;quot;size:&amp;quot;); // get the string index for the size block&lt;br /&gt;
&lt;br /&gt;
        rootScale  = (vector)llGetSubString(contents, rs_pos + 10, names_pos - 1); // get the root scale from the notecard&lt;br /&gt;
        names      = llParseString2List(llGetSubString(contents,names_pos + 6,pos_pos - 1),[&amp;quot;|&amp;quot;],[]); // Fun Fact! Support for correcting link order was added in May 2011 but wasn&#039;t actually implemented until November 2011!&lt;br /&gt;
        pos        = llParseString2List(llGetSubString(contents,pos_pos + 4,rot_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        rot        = llParseString2List(llGetSubString(contents,rot_pos + 4,size_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        size       = llParseString2List(llGetSubString(contents,size_pos + 5,-1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
&lt;br /&gt;
        contents = &amp;quot;&amp;quot;; // clearing memory up, we don&#039;t need the string in memory now.&lt;br /&gt;
        integer a = llGetListLength(names);&lt;br /&gt;
        integer b = llGetListLength(pos);&lt;br /&gt;
        if(b % a || llGetListLength(rot) % a || llGetListLength(size) % a){ // since the number of names corresponds to the number of prims, we can use modulus to ensure that the notecard doesn&#039;t have a corrupt export.&lt;br /&gt;
            llOwnerSay(&amp;quot;List Lengths do not match, possible corrupted notecard (&amp;quot; + llList2CSV([a,llGetListLength(pos),llGetListLength(rot),llGetListLength(size)]) + &amp;quot;)&amp;quot;);&lt;br /&gt;
        }else{&lt;br /&gt;
            llMessageLinked(LINK_THIS,b,&amp;quot;XDimportLength&amp;quot;,NULL_KEY); // notecard contents are valid, core script can start import now.&lt;br /&gt;
            llOwnerSay(&amp;quot;Do import now&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY &amp;amp;&amp;amp; llGetInventoryKey(notecard) != _notecard){&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer s, integer n, string m, key k){&lt;br /&gt;
        if(m == &amp;quot;XDimportLength&amp;quot; &amp;amp;&amp;amp; n == -1){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j=llGetListLength(pos);&lt;br /&gt;
            integer l;&lt;br /&gt;
            integer namesLength=llGetListLength(names);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                l = llListFindList(names, [llGetLinkName(2 + (i % namesLength))]) + (llFloor(i / namesLength) * namesLength); // this is to fix any bugs caused by link order changes (finally added in November 2011)&lt;br /&gt;
                llMessageLinked(s,i,llDumpList2String([llList2Vector(pos,l),llList2Rot(rot,l),llList2Vector(size,l)],&amp;quot;|&amp;quot;),import); // send the import string to the core OPA script&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(s,0,(string)rootScale, op_alter_rootScale); // once we&#039;re done importing the position, rotation &amp;amp; size values for the animation frames, update the root scale to the value used in the creation of the animation frames.&lt;br /&gt;
            llOwnerSay(&amp;quot;Done importing&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    touch_start(integer t){&lt;br /&gt;
        llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
[[Category:Open Prim Animator|Notecard Import]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Notecard_Import&amp;diff=1159607</id>
		<title>Open Prim Animator/Notecard Import</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Notecard_Import&amp;diff=1159607"/>
		<updated>2011-12-14T12:23:32Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
//!  @brief Imports a set of animation frames from a notecard&lt;br /&gt;
/**&lt;br /&gt;
*    @author SignpostMarv Martin&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
//!  name of notecard to parse&lt;br /&gt;
string notecard = &amp;quot;Open Prim Animator: Import&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  inventory key of notecard&lt;br /&gt;
key   _notecard;&lt;br /&gt;
&lt;br /&gt;
//!  Temporarily stores the entire notecard contents&lt;br /&gt;
string contents;&lt;br /&gt;
&lt;br /&gt;
//!  Since llGetNotecardLine() only reads the first 255 bytes of a notecard line, we need to temporarily store the notecard contents in a list before dumping it to the contents string.&lt;br /&gt;
list   _contents;&lt;br /&gt;
&lt;br /&gt;
//!  Whilst not truly multi-threaded, this script attempts non-sequential loading of the notecard (as opposed to sequential loading), theoretically providing some small performance gain&lt;br /&gt;
list multithread_fetch = [];&lt;br /&gt;
&lt;br /&gt;
//!  dataserver query variable used to determine how many lines are in a notecard- needed to pre-populate multithread_fetch to the correct size.&lt;br /&gt;
key nlq;&lt;br /&gt;
&lt;br /&gt;
//!  import command&lt;br /&gt;
key import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  export command&lt;br /&gt;
key export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  command for updating the root scale in the core OPA script&lt;br /&gt;
key op_alter_rootScale = &amp;quot;f9d3389e-a78c-43f8-9e35-c11adec112a5&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  command for restoring link order&lt;br /&gt;
key op_adjust_link_order_by_names = &amp;quot;e907917f-e5a3-490e-aaac-4596a0dc176d&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of link names&lt;br /&gt;
list names;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of animation frame positions&lt;br /&gt;
list pos;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of animation frame rotations&lt;br /&gt;
list rot;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of animation frame sizes&lt;br /&gt;
list size;&lt;br /&gt;
&lt;br /&gt;
//!  temporary store of root scale. This is needed in case a new animation was generated on an object with a different root scale to the prim the object the notecard is being imported to&lt;br /&gt;
vector rootScale;&lt;br /&gt;
&lt;br /&gt;
//!  I think this is here solely due to copypasta.&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s=1000;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(_export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        if(llGetInventoryType(notecard) == INVENTORY_NOTECARD){ // if the specified notecard is in the object,&lt;br /&gt;
            _notecard = llGetInventoryKey(notecard); // get the inventory key&lt;br /&gt;
            state num_lines; // then attempt to get the number of lines in the notecard&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY){ // if the inventory has changed (e.g. if the notecard *wasn&#039;t* in the object),&lt;br /&gt;
            llResetScript(); // restart the script&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state num_lines{ // there should probably be a CHANGED_INVENTORY check in case the scripts are running reaaaaallllyyyy slow.&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        nlq = llGetNumberOfNotecardLines(notecard); // attempt to get the number of lines in the notecard&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        if(q == nlq){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j = (integer)m;&lt;br /&gt;
            list    k = []; // declaring list k = []; isn&#039;t exactly necessary, you could do list k;&lt;br /&gt;
            list    l = [];&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){ // since we don&#039;t have the concept of transactions in LSL scripts, we&#039;re going to build up these lists separately &lt;br /&gt;
                k += [NULL_KEY];&lt;br /&gt;
                l += [NULL_KEY];&lt;br /&gt;
            }&lt;br /&gt;
            _contents = k; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            multithread_fetch = l; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            k = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            l = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            state mtf; // now we&#039;ve pre-populated the lists to the correct size, start the &amp;quot;multi-threaded fetch&amp;quot; of notecard contents.&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state mtf{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer i;&lt;br /&gt;
        integer j=llGetListLength(multithread_fetch);&lt;br /&gt;
        for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
            multithread_fetch = llListReplaceList(multithread_fetch,[llGetNotecardLine(notecard,i)],i,i); // sets the notecard fetching away&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        integer i = llListFindList(multithread_fetch,[q]);&lt;br /&gt;
        if(i &amp;gt;= 0){&lt;br /&gt;
            _contents = llListReplaceList(_contents,[m],i,i); // the traditional method of notecard fetching in LSL is single-threaded, getting one line at a time&lt;br /&gt;
        }&lt;br /&gt;
        if(llListFindList(_contents,[NULL_KEY]) == -1){ // since we started out with a NULLL_KEY-filled list, if there aren&#039;t any NUL_KEY in the list then we know it&#039;s done. caveat scriptor: since key and string types are interchangeable &lt;br /&gt;
            contents = llDumpList2String(_contents,&amp;quot;&amp;quot;);&lt;br /&gt;
            state done_reading;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state_exit(){&lt;br /&gt;
        _contents = [];&lt;br /&gt;
        multithread_fetch = [];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state done_reading{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer rs_pos    = llSubStringIndex(contents,&amp;quot;rootscale:&amp;quot;);&lt;br /&gt;
        integer names_pos = llSubStringIndex(contents,&amp;quot;names:&amp;quot;);&lt;br /&gt;
        integer pos_pos   = llSubStringIndex(contents,&amp;quot;pos:&amp;quot;);&lt;br /&gt;
        integer rot_pos   = llSubStringIndex(contents,&amp;quot;rot:&amp;quot;);&lt;br /&gt;
        integer size_pos  = llSubStringIndex(contents,&amp;quot;size:&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        rootScale  = (vector)llGetSubString(contents, rs_pos + 10, names_pos - 1);&lt;br /&gt;
        names      = llParseString2List(llGetSubString(contents,names_pos + 6,pos_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        pos        = llParseString2List(llGetSubString(contents,pos_pos + 4,rot_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        rot        = llParseString2List(llGetSubString(contents,rot_pos + 4,size_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        size       = llParseString2List(llGetSubString(contents,size_pos + 5,-1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
&lt;br /&gt;
        contents = &amp;quot;&amp;quot;; // clearing memory up, we don&#039;t need the string in memory now.&lt;br /&gt;
        integer a = llGetListLength(names);&lt;br /&gt;
        integer b = llGetListLength(pos);&lt;br /&gt;
        if(b % a || llGetListLength(rot) % a || llGetListLength(size) % a){&lt;br /&gt;
            llOwnerSay(&amp;quot;List Lengths do not match, possible corrupted notecard (&amp;quot; + llList2CSV([a,llGetListLength(pos),llGetListLength(rot),llGetListLength(size)]) + &amp;quot;)&amp;quot;);&lt;br /&gt;
        }else{&lt;br /&gt;
            llMessageLinked(LINK_THIS,b,&amp;quot;XDimportLength&amp;quot;,NULL_KEY);&lt;br /&gt;
            llOwnerSay(&amp;quot;Do import now&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY &amp;amp;&amp;amp; llGetInventoryKey(notecard) != _notecard){&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer s, integer n, string m, key k){&lt;br /&gt;
        if(m == &amp;quot;XDimportLength&amp;quot; &amp;amp;&amp;amp; n == -1){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j=llGetListLength(pos);&lt;br /&gt;
            integer l;&lt;br /&gt;
            integer namesLength=llGetListLength(names);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                l = llListFindList(names, [llGetLinkName(2 + (i % namesLength))]) + (llFloor(i / namesLength) * namesLength); // this is to fix any bugs caused by link order changes&lt;br /&gt;
                llMessageLinked(s,i,llDumpList2String([llList2Vector(pos,l),llList2Rot(rot,l),llList2Vector(size,l)],&amp;quot;|&amp;quot;),import);&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(s,0,(string)rootScale, op_alter_rootScale);&lt;br /&gt;
            llOwnerSay(&amp;quot;Done importing&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    touch_start(integer t){&lt;br /&gt;
        llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
[[Category:Open Prim Animator|Notecard Import]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Notecard_Import&amp;diff=1159606</id>
		<title>Open Prim Animator/Notecard Import</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Notecard_Import&amp;diff=1159606"/>
		<updated>2011-12-14T11:59:59Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: wikitypo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
string notecard = &amp;quot;Open Prim Animator: Import&amp;quot;;&lt;br /&gt;
key   _notecard;&lt;br /&gt;
string contents;&lt;br /&gt;
list   _contents;&lt;br /&gt;
list multithread_fetch = [];&lt;br /&gt;
key nlq;&lt;br /&gt;
key import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
key export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
key op_alter_rootScale = &amp;quot;f9d3389e-a78c-43f8-9e35-c11adec112a5&amp;quot;;&lt;br /&gt;
key op_adjust_link_order_by_names = &amp;quot;e907917f-e5a3-490e-aaac-4596a0dc176d&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
list names;&lt;br /&gt;
list pos;&lt;br /&gt;
list rot;&lt;br /&gt;
list size;&lt;br /&gt;
vector rootScale;&lt;br /&gt;
&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s=1000;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(_export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        if(llGetInventoryType(notecard) == INVENTORY_NOTECARD){&lt;br /&gt;
            _notecard = llGetInventoryKey(notecard);&lt;br /&gt;
            state num_lines;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY){&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state num_lines{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        nlq = llGetNumberOfNotecardLines(notecard);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        if(q == nlq){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j = (integer)m;&lt;br /&gt;
            list    k = []; // declaring list k = []; isn&#039;t exactly necessary, you could do list k;&lt;br /&gt;
            list    l = [];&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){ // since we don&#039;t have the concept of transactions in LSL scripts, we&#039;re going to build up these lists separately &lt;br /&gt;
                k += [NULL_KEY];&lt;br /&gt;
                l += [NULL_KEY];&lt;br /&gt;
            }&lt;br /&gt;
            _contents = k; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            multithread_fetch = l; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            k = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            l = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            state mtf;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state mtf{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer i;&lt;br /&gt;
        integer j=llGetListLength(multithread_fetch);&lt;br /&gt;
        for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
            multithread_fetch = llListReplaceList(multithread_fetch,[llGetNotecardLine(notecard,i)],i,i); // sets the notecard fetching away&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        integer i = llListFindList(multithread_fetch,[q]);&lt;br /&gt;
        if(i &amp;gt;= 0){&lt;br /&gt;
            _contents = llListReplaceList(_contents,[m],i,i); // the traditional method of notecard fetching in LSL is single-threaded, getting one line at a time&lt;br /&gt;
        }&lt;br /&gt;
        if(llListFindList(_contents,[NULL_KEY]) == -1){ // since we started out with a NULLL_KEY-filled list, if there aren&#039;t any NUL_KEY in the list then we know it&#039;s done. caveat scriptor: since key and string types are interchangeable &lt;br /&gt;
            contents = llDumpList2String(_contents,&amp;quot;&amp;quot;);&lt;br /&gt;
            state done_reading;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state_exit(){&lt;br /&gt;
        _contents = [];&lt;br /&gt;
        multithread_fetch = [];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state done_reading{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer rs_pos    = llSubStringIndex(contents,&amp;quot;rootscale:&amp;quot;);&lt;br /&gt;
        integer names_pos = llSubStringIndex(contents,&amp;quot;names:&amp;quot;);&lt;br /&gt;
        integer pos_pos   = llSubStringIndex(contents,&amp;quot;pos:&amp;quot;);&lt;br /&gt;
        integer rot_pos   = llSubStringIndex(contents,&amp;quot;rot:&amp;quot;);&lt;br /&gt;
        integer size_pos  = llSubStringIndex(contents,&amp;quot;size:&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        rootScale  = (vector)llGetSubString(contents, rs_pos + 10, names_pos - 1);&lt;br /&gt;
        names      = llParseString2List(llGetSubString(contents,names_pos + 6,pos_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        pos        = llParseString2List(llGetSubString(contents,pos_pos + 4,rot_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        rot        = llParseString2List(llGetSubString(contents,rot_pos + 4,size_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        size       = llParseString2List(llGetSubString(contents,size_pos + 5,-1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
&lt;br /&gt;
        contents = &amp;quot;&amp;quot;; // clearing memory up, we don&#039;t need the string in memory now.&lt;br /&gt;
        integer a = llGetListLength(names);&lt;br /&gt;
        integer b = llGetListLength(pos);&lt;br /&gt;
        if(b % a || llGetListLength(rot) % a || llGetListLength(size) % a){&lt;br /&gt;
            llOwnerSay(&amp;quot;List Lengths do not match, possible corrupted notecard (&amp;quot; + llList2CSV([a,llGetListLength(pos),llGetListLength(rot),llGetListLength(size)]) + &amp;quot;)&amp;quot;);&lt;br /&gt;
        }else{&lt;br /&gt;
            llMessageLinked(LINK_THIS,b,&amp;quot;XDimportLength&amp;quot;,NULL_KEY);&lt;br /&gt;
            llOwnerSay(&amp;quot;Do import now&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY &amp;amp;&amp;amp; llGetInventoryKey(notecard) != _notecard){&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer s, integer n, string m, key k){&lt;br /&gt;
        if(m == &amp;quot;XDimportLength&amp;quot; &amp;amp;&amp;amp; n == -1){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j=llGetListLength(pos);&lt;br /&gt;
            integer l;&lt;br /&gt;
            integer namesLength=llGetListLength(names);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                l = llListFindList(names, [llGetLinkName(2 + (i % namesLength))]) + (llFloor(i / namesLength) * namesLength); // this is to fix any bugs caused by link order changes&lt;br /&gt;
                llMessageLinked(s,i,llDumpList2String([llList2Vector(pos,l),llList2Rot(rot,l),llList2Vector(size,l)],&amp;quot;|&amp;quot;),import);&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(s,0,(string)rootScale, op_alter_rootScale);&lt;br /&gt;
            llOwnerSay(&amp;quot;Done importing&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    touch_start(integer t){&lt;br /&gt;
        llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
[[Category:Open Prim Animator|Notecard Import]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Notecard_Import&amp;diff=1159605</id>
		<title>Open Prim Animator/Notecard Import</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Notecard_Import&amp;diff=1159605"/>
		<updated>2011-12-14T11:59:14Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: committing notecard import script for Open Prim Animator/Import-Export&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
string notecard = &amp;quot;Open Prim Animator: Import&amp;quot;;&lt;br /&gt;
key   _notecard;&lt;br /&gt;
string contents;&lt;br /&gt;
list   _contents;&lt;br /&gt;
list multithread_fetch = [];&lt;br /&gt;
key nlq;&lt;br /&gt;
key import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
key export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
key op_alter_rootScale = &amp;quot;f9d3389e-a78c-43f8-9e35-c11adec112a5&amp;quot;;&lt;br /&gt;
key op_adjust_link_order_by_names = &amp;quot;e907917f-e5a3-490e-aaac-4596a0dc176d&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
list names;&lt;br /&gt;
list pos;&lt;br /&gt;
list rot;&lt;br /&gt;
list size;&lt;br /&gt;
vector rootScale;&lt;br /&gt;
&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s=1000;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(_export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        if(llGetInventoryType(notecard) == INVENTORY_NOTECARD){&lt;br /&gt;
            _notecard = llGetInventoryKey(notecard);&lt;br /&gt;
            state num_lines;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY){&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state num_lines{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        nlq = llGetNumberOfNotecardLines(notecard);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        if(q == nlq){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j = (integer)m;&lt;br /&gt;
            list    k = []; // declaring list k = []; isn&#039;t exactly necessary, you could do list k;&lt;br /&gt;
            list    l = [];&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){ // since we don&#039;t have the concept of transactions in LSL scripts, we&#039;re going to build up these lists separately &lt;br /&gt;
                k += [NULL_KEY];&lt;br /&gt;
                l += [NULL_KEY];&lt;br /&gt;
            }&lt;br /&gt;
            _contents = k; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            multithread_fetch = l; // this is where we do the atomic writes due to lack of transactions on variables&lt;br /&gt;
            k = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            l = []; // cleaning up the local variable on purpose in case the LSL VM executing this script is inefficient&lt;br /&gt;
            state mtf;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state mtf{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer i;&lt;br /&gt;
        integer j=llGetListLength(multithread_fetch);&lt;br /&gt;
        for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
            multithread_fetch = llListReplaceList(multithread_fetch,[llGetNotecardLine(notecard,i)],i,i); // sets the notecard fetching away&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    dataserver(key q, string m){&lt;br /&gt;
        integer i = llListFindList(multithread_fetch,[q]);&lt;br /&gt;
        if(i &amp;gt;= 0){&lt;br /&gt;
            _contents = llListReplaceList(_contents,[m],i,i); // the traditional method of notecard fetching in LSL is single-threaded, getting one line at a time&lt;br /&gt;
        }&lt;br /&gt;
        if(llListFindList(_contents,[NULL_KEY]) == -1){ // since we started out with a NULLL_KEY-filled list, if there aren&#039;t any NUL_KEY in the list then we know it&#039;s done. caveat scriptor: since key and string types are interchangeable &lt;br /&gt;
            contents = llDumpList2String(_contents,&amp;quot;&amp;quot;);&lt;br /&gt;
            state done_reading;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    state_exit(){&lt;br /&gt;
        _contents = [];&lt;br /&gt;
        multithread_fetch = [];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
state done_reading{&lt;br /&gt;
    state_entry(){&lt;br /&gt;
        integer rs_pos    = llSubStringIndex(contents,&amp;quot;rootscale:&amp;quot;);&lt;br /&gt;
        integer names_pos = llSubStringIndex(contents,&amp;quot;names:&amp;quot;);&lt;br /&gt;
        integer pos_pos   = llSubStringIndex(contents,&amp;quot;pos:&amp;quot;);&lt;br /&gt;
        integer rot_pos   = llSubStringIndex(contents,&amp;quot;rot:&amp;quot;);&lt;br /&gt;
        integer size_pos  = llSubStringIndex(contents,&amp;quot;size:&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        rootScale  = (vector)llGetSubString(contents, rs_pos + 10, names_pos - 1);&lt;br /&gt;
        names      = llParseString2List(llGetSubString(contents,names_pos + 6,pos_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        pos        = llParseString2List(llGetSubString(contents,pos_pos + 4,rot_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        rot        = llParseString2List(llGetSubString(contents,rot_pos + 4,size_pos - 1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
        size       = llParseString2List(llGetSubString(contents,size_pos + 5,-1),[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
&lt;br /&gt;
        contents = &amp;quot;&amp;quot;; // clearing memory up, we don&#039;t need the string in memory now.&lt;br /&gt;
        integer a = llGetListLength(names);&lt;br /&gt;
        integer b = llGetListLength(pos);&lt;br /&gt;
        if(b % a || llGetListLength(rot) % a || llGetListLength(size) % a){&lt;br /&gt;
            llOwnerSay(&amp;quot;List Lengths do not match, possible corrupted notecard (&amp;quot; + llList2CSV([a,llGetListLength(pos),llGetListLength(rot),llGetListLength(size)]) + &amp;quot;)&amp;quot;);&lt;br /&gt;
        }else{&lt;br /&gt;
            llMessageLinked(LINK_THIS,b,&amp;quot;XDimportLength&amp;quot;,NULL_KEY);&lt;br /&gt;
            llOwnerSay(&amp;quot;Do import now&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    changed(integer c){&lt;br /&gt;
        if(c &amp;amp; CHANGED_INVENTORY &amp;amp;&amp;amp; llGetInventoryKey(notecard) != _notecard){&lt;br /&gt;
            llResetScript();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    link_message(integer s, integer n, string m, key k){&lt;br /&gt;
        if(m == &amp;quot;XDimportLength&amp;quot; &amp;amp;&amp;amp; n == -1){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j=llGetListLength(pos);&lt;br /&gt;
            integer l;&lt;br /&gt;
            integer namesLength=llGetListLength(names);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                l = llListFindList(names, [llGetLinkName(2 + (i % namesLength))]) + (llFloor(i / namesLength) * namesLength); // this is to fix any bugs caused by link order changes&lt;br /&gt;
                llMessageLinked(s,i,llDumpList2String([llList2Vector(pos,l),llList2Rot(rot,l),llList2Vector(size,l)],&amp;quot;|&amp;quot;),import);&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(s,0,(string)rootScale, op_alter_rootScale);&lt;br /&gt;
            llOwnerSay(&amp;quot;Done importing&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    touch_start(integer t){&lt;br /&gt;
        llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);   &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
[[Open Prim Animator|Notecard Import]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Import-Export&amp;diff=1159604</id>
		<title>Open Prim Animator/Import-Export</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Import-Export&amp;diff=1159604"/>
		<updated>2011-12-14T11:55:23Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: documentation, cat sort tweak&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
//!  @brief Animation export script for http://wiki.secondlife.com/wiki/Open_Prim_Animator&lt;br /&gt;
/**&lt;br /&gt;
*    @author SignpostMarv Martin&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
//!  Storing the names in exports allows us to remap links according to their current state&lt;br /&gt;
/**&lt;br /&gt;
*    we want to store the names because there are circumstances where the link order can change-&lt;br /&gt;
*      TPV object import/export&lt;br /&gt;
*      accidentally delinking objects etc.&lt;br /&gt;
*    Once an import has been parsed, the script checks it against the current object state to avoid the wrong prims being animated.&lt;br /&gt;
*    Since OPA doesn&#039;t animate prim cut/twist etc., this is essential to avoid any messed up animations.&lt;br /&gt;
*/&lt;br /&gt;
list names;&lt;br /&gt;
&lt;br /&gt;
//!  place-holder for all prim positions&lt;br /&gt;
list pos;&lt;br /&gt;
&lt;br /&gt;
//!  place-holder for all prim rotations&lt;br /&gt;
list rot;&lt;br /&gt;
&lt;br /&gt;
//!  place-holder for all prim scales&lt;br /&gt;
list size;&lt;br /&gt;
&lt;br /&gt;
//!  used to communicate with the core OPA script to trigger an import.&lt;br /&gt;
key import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  used to communicate with the core OPA script to trigger an export.&lt;br /&gt;
key export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  spits out the export document to chat so the user can copypasta to a notecard to allow the animation frames to be persisted.&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s = 249;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(&amp;quot;\n&amp;quot; + llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(&amp;quot;\n&amp;quot; + _export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//!  unlike (string)foo, truncate_float() attempts to &amp;quot;minify&amp;quot; the string so keep the size of the export document down.&lt;br /&gt;
/**&lt;br /&gt;
*    1.0 would be converted to &amp;quot;1&amp;quot;&lt;br /&gt;
*    0.1 would be converted to &amp;quot;.1&amp;quot;&lt;br /&gt;
*/&lt;br /&gt;
string truncate_float(float foo){&lt;br /&gt;
    if(foo == 0.0){&lt;br /&gt;
        return &amp;quot;0&amp;quot;;&lt;br /&gt;
    }else if(foo == (float)((integer)foo)){&lt;br /&gt;
        return (string)((integer)foo);&lt;br /&gt;
    }&lt;br /&gt;
    string bar = (string)foo;&lt;br /&gt;
    while(llGetSubString(bar,-1,-1) == &amp;quot;0&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);   &lt;br /&gt;
    }&lt;br /&gt;
    if(llGetSubString(bar,-1,-1) == &amp;quot;.&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);&lt;br /&gt;
    }&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//!  unlike (string)foo, truncate_vector() attempts to &amp;quot;minify&amp;quot; the string so keep the size of the export document down.&lt;br /&gt;
//!  @see truncate_float()&lt;br /&gt;
string truncate_vector(vector foo){&lt;br /&gt;
    if(foo == ZERO_VECTOR){&lt;br /&gt;
        return &amp;quot;&amp;lt;0,0,0&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    string bar = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.x) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.y) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.z) + &amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//!  unlike (string)foo, truncate_rotation() attempts to &amp;quot;minify&amp;quot; the string so keep the size of the export document down.&lt;br /&gt;
string truncate_rotation(rotation foo){&lt;br /&gt;
    if(foo == ZERO_ROTATION){&lt;br /&gt;
        return &amp;quot;&amp;lt;0,0,0,1&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    string bar = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.x) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.y) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.z) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.s) + &amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    link_message(integer s, integer n, string m, key k){&lt;br /&gt;
        if(k == export){&lt;br /&gt;
&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j;&lt;br /&gt;
&lt;br /&gt;
            if(n == 1){ // if n == 1, we&#039;re parsing link names&lt;br /&gt;
                names = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
            }else if(n == 2){ // if n == 2, we&#039;re parsing position vectors&lt;br /&gt;
                pos   = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(pos);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    pos = llListReplaceList(pos,[(vector)llList2String(pos,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }else if(n == 3){ // if n == 3, we&#039;re parsing rotations&lt;br /&gt;
                rot   = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(rot);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    rot = llListReplaceList(rot,[(rotation)llList2String(rot,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }else if(n == 4){ // if n == 4, we&#039;re parsing prim sizes&lt;br /&gt;
                size  = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(size);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    size = llListReplaceList(size,[(vector)llList2String(size,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if(names != [] &amp;amp;&amp;amp; pos != [] &amp;amp;&amp;amp; rot != [] &amp;amp;&amp;amp; size != []){ // start truncating the lists once they&#039;re all populated&lt;br /&gt;
&lt;br /&gt;
                llOwnerSay(&amp;quot;Exporting:&amp;quot;);&lt;br /&gt;
                export_string(&amp;quot;rootscale:&amp;quot; + truncate_vector(llGetScale()));&lt;br /&gt;
                export_string(&amp;quot;names:&amp;quot; + llDumpList2String(names,&amp;quot;|&amp;quot;));&lt;br /&gt;
                &lt;br /&gt;
                list bar = [];&lt;br /&gt;
                j= llGetListLength(pos);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){ // truncate the &lt;br /&gt;
                    bar += truncate_vector(llList2Vector(pos,i)); // minify each position vector&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;pos:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;)); // export minified position vectors to chat&lt;br /&gt;
&lt;br /&gt;
                bar = [];&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_rotation(llList2Rot(rot,i));  // minify each rotation&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;rot:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;)); // export minified rotations to chat&lt;br /&gt;
&lt;br /&gt;
                bar = [];&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_vector(llList2Vector(size,i)); // minify each size vector&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;size:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;)); // export minified sizes to chat&lt;br /&gt;
&lt;br /&gt;
                bar = []; // we&#039;re about to reset the script so this might be superfluous&lt;br /&gt;
                llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY); // re-open the menu&lt;br /&gt;
                llResetScript(); &lt;br /&gt;
            }&lt;br /&gt;
        }else if(k == import &amp;amp;&amp;amp; n == -1){&lt;br /&gt;
            llOwnerSay(&amp;quot;importing&amp;quot;);&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j=llGetListLength(pos);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                llMessageLinked(s,i,llDumpList2String([llList2Vector(pos,i),llList2Rot(rot,i),llList2Vector(size,i)],&amp;quot;|&amp;quot;),import);&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);&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;
[[Category:Open Prim Animator|Import/Export]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Import-Export&amp;diff=1159603</id>
		<title>Open Prim Animator/Import-Export</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Import-Export&amp;diff=1159603"/>
		<updated>2011-12-14T11:40:37Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: moar documentation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
//!  @brief Animation export script for http://wiki.secondlife.com/wiki/Open_Prim_Animator&lt;br /&gt;
/**&lt;br /&gt;
*    @author SignpostMarv Martin&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
//!  Storing the names in exports allows us to remap links according to their current state&lt;br /&gt;
/**&lt;br /&gt;
*    we want to store the names because there are circumstances where the link order can change-&lt;br /&gt;
*      TPV object import/export&lt;br /&gt;
*      accidentally delinking objects etc.&lt;br /&gt;
*    Once an import has been parsed, the script checks it against the current object state to avoid the wrong prims being animated.&lt;br /&gt;
*    Since OPA doesn&#039;t animate prim cut/twist etc., this is essential to avoid any messed up animations.&lt;br /&gt;
*/&lt;br /&gt;
list names;&lt;br /&gt;
&lt;br /&gt;
//!  place-holder for all prim positions&lt;br /&gt;
list pos;&lt;br /&gt;
&lt;br /&gt;
//!  place-holder for all prim rotations&lt;br /&gt;
list rot;&lt;br /&gt;
&lt;br /&gt;
//!  place-holder for all prim scales&lt;br /&gt;
list size;&lt;br /&gt;
&lt;br /&gt;
//!  used to communicate with the core OPA script to trigger an import.&lt;br /&gt;
key import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  used to communicate with the core OPA script to trigger an export.&lt;br /&gt;
key export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
//!  spits out the export document to chat so the user can copypasta to a notecard to allow the animation frames to be persisted.&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s = 249;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(&amp;quot;\n&amp;quot; + llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(&amp;quot;\n&amp;quot; + _export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//!  unlike (string)foo, truncate_float() attempts to &amp;quot;minify&amp;quot; the string so keep the size of the export document down.&lt;br /&gt;
/**&lt;br /&gt;
*    1.0 would be converted to &amp;quot;1&amp;quot;&lt;br /&gt;
*    0.1 would be converted to &amp;quot;.1&amp;quot;&lt;br /&gt;
*/&lt;br /&gt;
string truncate_float(float foo){&lt;br /&gt;
    if(foo == 0.0){&lt;br /&gt;
        return &amp;quot;0&amp;quot;;&lt;br /&gt;
    }else if(foo == (float)((integer)foo)){&lt;br /&gt;
        return (string)((integer)foo);&lt;br /&gt;
    }&lt;br /&gt;
    string bar = (string)foo;&lt;br /&gt;
    while(llGetSubString(bar,-1,-1) == &amp;quot;0&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);   &lt;br /&gt;
    }&lt;br /&gt;
    if(llGetSubString(bar,-1,-1) == &amp;quot;.&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);&lt;br /&gt;
    }&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//!  unlike (string)foo, truncate_vector() attempts to &amp;quot;minify&amp;quot; the string so keep the size of the export document down.&lt;br /&gt;
//!  @see truncate_float()&lt;br /&gt;
string truncate_vector(vector foo){&lt;br /&gt;
    if(foo == ZERO_VECTOR){&lt;br /&gt;
        return &amp;quot;&amp;lt;0,0,0&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    string bar = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.x) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.y) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.z) + &amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//!  unlike (string)foo, truncate_rotation() attempts to &amp;quot;minify&amp;quot; the string so keep the size of the export document down.&lt;br /&gt;
string truncate_rotation(rotation foo){&lt;br /&gt;
    if(foo == ZERO_ROTATION){&lt;br /&gt;
        return &amp;quot;&amp;lt;0,0,0,1&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    string bar = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.x) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.y) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.z) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.s) + &amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    link_message(integer s, integer n, string m, key k){&lt;br /&gt;
        if(k == export){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j;&lt;br /&gt;
            if(n == 1){&lt;br /&gt;
                names = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
            }else if(n == 2){&lt;br /&gt;
                pos   = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(pos);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    pos = llListReplaceList(pos,[(vector)llList2String(pos,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }else if(n == 3){&lt;br /&gt;
                rot   = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(rot);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    rot = llListReplaceList(rot,[(rotation)llList2String(rot,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }else if(n == 4){&lt;br /&gt;
                size  = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(size);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    size = llListReplaceList(size,[(vector)llList2String(size,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            if(names != [] &amp;amp;&amp;amp; pos != [] &amp;amp;&amp;amp; rot != [] &amp;amp;&amp;amp; size != []){&lt;br /&gt;
&lt;br /&gt;
                llOwnerSay(&amp;quot;Exporting:&amp;quot;);&lt;br /&gt;
                export_string(&amp;quot;rootscale:&amp;quot; + truncate_vector(llGetScale()));&lt;br /&gt;
                export_string(&amp;quot;names:&amp;quot; + llDumpList2String(names,&amp;quot;|&amp;quot;));&lt;br /&gt;
                &lt;br /&gt;
                list bar = [];&lt;br /&gt;
                j= llGetListLength(pos);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_vector(llList2Vector(pos,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;pos:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_rotation(llList2Rot(rot,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;rot:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_vector(llList2Vector(size,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;size:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);&lt;br /&gt;
                llResetScript();&lt;br /&gt;
            }&lt;br /&gt;
        }else if(k == import &amp;amp;&amp;amp; n == -1){&lt;br /&gt;
            llOwnerSay(&amp;quot;importing&amp;quot;);&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j=llGetListLength(pos);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                llMessageLinked(s,i,llDumpList2String([llList2Vector(pos,i),llList2Rot(rot,i),llList2Vector(size,i)],&amp;quot;|&amp;quot;),import);&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);&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;
[[Category:Open Prim Animator]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Import-Export&amp;diff=1159602</id>
		<title>Open Prim Animator/Import-Export</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Import-Export&amp;diff=1159602"/>
		<updated>2011-12-14T11:21:05Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: comments for names property.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
//!  @brief Animation export script for http://wiki.secondlife.com/wiki/Open_Prim_Animator&lt;br /&gt;
/**&lt;br /&gt;
*    @author SignpostMarv Martin&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
//!  Storing the names in exports allows us to remap links according to their current state&lt;br /&gt;
/**&lt;br /&gt;
*    we want to store the names because there are circumstances where the link order can change-&lt;br /&gt;
*      TPV object import/export&lt;br /&gt;
*      accidentally delinking objects etc.&lt;br /&gt;
*    Once an import has been parsed, the script checks it against the current object state to avoid the wrong prims being animated.&lt;br /&gt;
*    Since OPA doesn&#039;t animate prim cut/twist etc., this is essential to avoid any messed up animations.&lt;br /&gt;
*/&lt;br /&gt;
list names;&lt;br /&gt;
list pos;&lt;br /&gt;
list rot;&lt;br /&gt;
list size;&lt;br /&gt;
&lt;br /&gt;
key import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
key export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s = 249;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(&amp;quot;\n&amp;quot; + llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(&amp;quot;\n&amp;quot; + _export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string truncate_float(float foo){&lt;br /&gt;
    if(foo == 0.0){&lt;br /&gt;
        return &amp;quot;0&amp;quot;;&lt;br /&gt;
    }else if(foo == (float)((integer)foo)){&lt;br /&gt;
        return (string)((integer)foo);&lt;br /&gt;
    }&lt;br /&gt;
    string bar = (string)foo;&lt;br /&gt;
    while(llGetSubString(bar,-1,-1) == &amp;quot;0&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);   &lt;br /&gt;
    }&lt;br /&gt;
    if(llGetSubString(bar,-1,-1) == &amp;quot;.&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);&lt;br /&gt;
    }&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string truncate_vector(vector foo){&lt;br /&gt;
    if(foo == ZERO_VECTOR){&lt;br /&gt;
        return &amp;quot;&amp;lt;0,0,0&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    string bar = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.x) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.y) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.z) + &amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string truncate_rotation(rotation foo){&lt;br /&gt;
    if(foo == ZERO_ROTATION){&lt;br /&gt;
        return &amp;quot;&amp;lt;0,0,0,1&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    string bar = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.x) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.y) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.z) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.s) + &amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    link_message(integer s, integer n, string m, key k){&lt;br /&gt;
        if(k == export){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j;&lt;br /&gt;
            if(n == 1){&lt;br /&gt;
                names = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
            }else if(n == 2){&lt;br /&gt;
                pos   = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(pos);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    pos = llListReplaceList(pos,[(vector)llList2String(pos,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }else if(n == 3){&lt;br /&gt;
                rot   = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(rot);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    rot = llListReplaceList(rot,[(rotation)llList2String(rot,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }else if(n == 4){&lt;br /&gt;
                size  = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(size);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    size = llListReplaceList(size,[(vector)llList2String(size,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            if(names != [] &amp;amp;&amp;amp; pos != [] &amp;amp;&amp;amp; rot != [] &amp;amp;&amp;amp; size != []){&lt;br /&gt;
&lt;br /&gt;
                llOwnerSay(&amp;quot;Exporting:&amp;quot;);&lt;br /&gt;
                export_string(&amp;quot;rootscale:&amp;quot; + truncate_vector(llGetScale()));&lt;br /&gt;
                export_string(&amp;quot;names:&amp;quot; + llDumpList2String(names,&amp;quot;|&amp;quot;));&lt;br /&gt;
                &lt;br /&gt;
                list bar = [];&lt;br /&gt;
                j= llGetListLength(pos);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_vector(llList2Vector(pos,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;pos:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_rotation(llList2Rot(rot,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;rot:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_vector(llList2Vector(size,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;size:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);&lt;br /&gt;
                llResetScript();&lt;br /&gt;
            }&lt;br /&gt;
        }else if(k == import &amp;amp;&amp;amp; n == -1){&lt;br /&gt;
            llOwnerSay(&amp;quot;importing&amp;quot;);&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j=llGetListLength(pos);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                llMessageLinked(s,i,llDumpList2String([llList2Vector(pos,i),llList2Rot(rot,i),llList2Vector(size,i)],&amp;quot;|&amp;quot;),import);&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);&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;
[[Category:Open Prim Animator]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Category:Open_Prim_Animator&amp;diff=1159601</id>
		<title>Category:Open Prim Animator</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Category:Open_Prim_Animator&amp;diff=1159601"/>
		<updated>2011-12-14T11:17:10Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: category blurb&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Category for scripts relating to the [[Open Prim Animator]] LSL prim animation script.&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator&amp;diff=1159600</id>
		<title>Open Prim Animator</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator&amp;diff=1159600"/>
		<updated>2011-12-14T11:16:25Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: categorisation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
// Open Prim Animator - by Todd Borst&lt;br /&gt;
// Extensive Modifications by SignpostMarv Martin&lt;br /&gt;
 &lt;br /&gt;
// This is provided AS IS without support.  Please don&#039;t bug me demanding &lt;br /&gt;
// help or custom work for this free script.&lt;br /&gt;
 &lt;br /&gt;
// Summary: This is a simple prim animation script.  Just add this script&lt;br /&gt;
// to your object and a dialog will automatically pop up for you to use.&lt;br /&gt;
 &lt;br /&gt;
// Features:&lt;br /&gt;
// -Single script &amp;quot;Prim Puppeteer&amp;quot; like animation tool&lt;br /&gt;
// -Playback controllable through external scripts&lt;br /&gt;
// -Animation is scalable and resizeable&lt;br /&gt;
// -On-touch trigger built-in&lt;br /&gt;
// -Completely free and open sourced &lt;br /&gt;
 &lt;br /&gt;
// License:&lt;br /&gt;
// You are welcome to use this anyway you like, even bring to other grids&lt;br /&gt;
// outside of Second Life.  If you try to sell what I&#039;m giving away for&lt;br /&gt;
// free, you will be cursed with unimaginably bad juju.&lt;br /&gt;
 &lt;br /&gt;
integer COMMAND_CHANNEL = 32;&lt;br /&gt;
 &lt;br /&gt;
integer primCount = 0;&lt;br /&gt;
integer commandListenerHandle = -1;&lt;br /&gt;
 &lt;br /&gt;
list posList     = [];&lt;br /&gt;
list rotList     = [];&lt;br /&gt;
list scaleList   = [];&lt;br /&gt;
integer currentSnapshot   = 0;&lt;br /&gt;
integer recordedSnapshots = 0;&lt;br /&gt;
 &lt;br /&gt;
vector rootScale   = ZERO_VECTOR;&lt;br /&gt;
vector scaleChange = &amp;lt;1,1,1&amp;gt;;&lt;br /&gt;
 &lt;br /&gt;
// For tracking memory usage.  The amount of snapshots you can record is based&lt;br /&gt;
// on the number of prims and available memory.  Less prims = more snapshots&lt;br /&gt;
integer maxMemory  = 0;&lt;br /&gt;
integer freeMemory = 0;&lt;br /&gt;
 &lt;br /&gt;
integer playAnimationStyle = 0;&lt;br /&gt;
// The values for playAnimationStyle means&lt;br /&gt;
// 0 = no animation playing&lt;br /&gt;
// 1 = play animation once&lt;br /&gt;
// 2 = play animation looping&lt;br /&gt;
 &lt;br /&gt;
// This function is used to display a recorded snapshot&lt;br /&gt;
showSnapshot(integer snapNumber)&lt;br /&gt;
{&lt;br /&gt;
    if(snapNumber &amp;gt; 0 &amp;amp;&amp;amp; snapNumber &amp;lt;= recordedSnapshots )&lt;br /&gt;
    {&lt;br /&gt;
        integer i = 0;&lt;br /&gt;
        vector   pos;&lt;br /&gt;
        rotation rot;&lt;br /&gt;
        vector   scale;&lt;br /&gt;
 &lt;br /&gt;
        vector rootPos = llGetPos();&lt;br /&gt;
 &lt;br /&gt;
        // Might want to move llGetRot() into the loop for fast rotating objects.&lt;br /&gt;
        // Rotation during the animation playback may cause errors.&lt;br /&gt;
        rotation rootRot = llGetRot();&lt;br /&gt;
&lt;br /&gt;
        list params = [];&lt;br /&gt;
 &lt;br /&gt;
        //2 is the first linked prim number.&lt;br /&gt;
        for( i = 2; i &amp;lt;= primCount; i++)&lt;br /&gt;
        {&lt;br /&gt;
            pos     = llList2Vector(posList,((snapNumber-1)*(primCount-1))+(i-2));&lt;br /&gt;
            rot     = llList2Rot(rotList,((snapNumber-1)*(primCount-1))+(i-2));&lt;br /&gt;
            scale   = llList2Vector(scaleList,((snapNumber-1)*(primCount-1))+(i-2));&lt;br /&gt;
 &lt;br /&gt;
            //Adjust for scale changes&lt;br /&gt;
            if( rootScale.x != 1.0 || rootScale.y != 1.0 || rootScale.z != 1.0 )&lt;br /&gt;
            {&lt;br /&gt;
                pos.x *= scaleChange.x;&lt;br /&gt;
                pos.y *= scaleChange.y;&lt;br /&gt;
                pos.z *= scaleChange.z;&lt;br /&gt;
                scale.x *= scaleChange.x;&lt;br /&gt;
                scale.y *= scaleChange.y;&lt;br /&gt;
                scale.z *= scaleChange.z;&lt;br /&gt;
            }&lt;br /&gt;
            params += [&lt;br /&gt;
                PRIM_LINK_TARGET,&lt;br /&gt;
                    i,&lt;br /&gt;
                PRIM_POSITION,&lt;br /&gt;
                    pos,&lt;br /&gt;
                PRIM_ROTATION,&lt;br /&gt;
                    rot/rootRot,&lt;br /&gt;
                PRIM_SIZE,&lt;br /&gt;
                    scale&lt;br /&gt;
            ];&lt;br /&gt;
 &lt;br /&gt;
            if(llGetListLength(params) &amp;gt; 64){&lt;br /&gt;
                llSetLinkPrimitiveParamsFast(LINK_THIS,params);&lt;br /&gt;
                params = [];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        if(llGetListLength(params) &amp;gt; 0){&lt;br /&gt;
            llSetLinkPrimitiveParamsFast(LINK_THIS,params);&lt;br /&gt;
            params = [];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// This function is used to start a sequential animation playback.&lt;br /&gt;
// If the delay speed is set too low, the script might not be able to keep up.&lt;br /&gt;
playAnimation(float delay, integer loop)&lt;br /&gt;
{&lt;br /&gt;
    if(delay &amp;lt; 0.1) delay = 1.0;&lt;br /&gt;
 &lt;br /&gt;
    if( loop == FALSE)&lt;br /&gt;
        playAnimationStyle = 1;&lt;br /&gt;
    else&lt;br /&gt;
        playAnimationStyle = 2;&lt;br /&gt;
 &lt;br /&gt;
    if (recordedSnapshots &amp;gt;= 1)&lt;br /&gt;
        llSetTimerEvent(delay);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// This shows the edit menu&lt;br /&gt;
showMenuDialog()&lt;br /&gt;
{&lt;br /&gt;
    return; // comment out line to re-enable menu&lt;br /&gt;
    string temp = (string)((float)freeMemory/(float)maxMemory * 100.0);&lt;br /&gt;
    string menuText = &amp;quot;Available Memory: &amp;quot; + (string)freeMemory + &amp;quot; (&amp;quot; + llGetSubString(temp, 0, 4) +&amp;quot;%)&amp;quot; +&lt;br /&gt;
    &amp;quot;\nCurrent Snapshot: &amp;quot; + (string)currentSnapshot +&amp;quot;\tSnapshots Recorded: &amp;quot; + (string)recordedSnapshots +&lt;br /&gt;
    &amp;quot;\n\n[ Record ] - Record a snapshot of prim positions\n[ Play ] - Play back all the recorded snapshots\n[ Publish ] - Finish the recording process\n[ Show Next ] - Show the next snapshot\n[ Show Prev ] - Show the previous snapshot&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
    llDialog(llGetOwner(), menuText, [&amp;quot;Record&amp;quot;,&amp;quot;Play&amp;quot;,&amp;quot;Publish&amp;quot;,&amp;quot;Show Prev&amp;quot;,&amp;quot;Show Next&amp;quot;,&amp;quot;Loop&amp;quot;,&amp;quot;Stop&amp;quot;,&amp;quot;Export&amp;quot;], COMMAND_CHANNEL);&lt;br /&gt;
}&lt;br /&gt;
string truncate_float(float foo){&lt;br /&gt;
    if(foo == 0.0){&lt;br /&gt;
        return &amp;quot;0&amp;quot;;&lt;br /&gt;
    }else if(foo == (float)((integer)foo)){&lt;br /&gt;
        return (string)((integer)foo);&lt;br /&gt;
    }&lt;br /&gt;
    string bar = (string)foo;&lt;br /&gt;
    while(llGetSubString(bar,-1,-1) == &amp;quot;0&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);   &lt;br /&gt;
    }&lt;br /&gt;
    if(llGetSubString(bar,-1,-1) == &amp;quot;.&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);&lt;br /&gt;
    }&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
key op_import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
key op_export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
key op_alter_rootScale = &amp;quot;f9d3389e-a78c-43f8-9e35-c11adec112a5&amp;quot;;&lt;br /&gt;
calc_scaleChange(){&lt;br /&gt;
    if (rootScale != ZERO_VECTOR){&lt;br /&gt;
        vector newScale = llGetScale();&lt;br /&gt;
        //since change_scale is triggered even with linked prim changes,&lt;br /&gt;
        //this is to filter out non-root changes.&lt;br /&gt;
        if( ( newScale.x / rootScale.x) != scaleChange.x ||&lt;br /&gt;
            ( newScale.y / rootScale.y) != scaleChange.y ||&lt;br /&gt;
            ( newScale.z / rootScale.z) != scaleChange.z )&lt;br /&gt;
        {&lt;br /&gt;
            scaleChange.x = newScale.x / rootScale.x;&lt;br /&gt;
            scaleChange.y = newScale.y / rootScale.y;&lt;br /&gt;
            scaleChange.z = newScale.z / rootScale.z;&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;
        maxMemory = llGetFreeMemory();&lt;br /&gt;
        freeMemory = llGetFreeMemory();&lt;br /&gt;
 &lt;br /&gt;
        primCount = llGetNumberOfPrims();&lt;br /&gt;
        commandListenerHandle = llListen(COMMAND_CHANNEL,&amp;quot;&amp;quot;, llGetOwner(), &amp;quot;&amp;quot;);&lt;br /&gt;
        showMenuDialog();&lt;br /&gt;
 &lt;br /&gt;
        //setting initial root scale.  this allows the animation to scale if the root size is changed afterwards.&lt;br /&gt;
        rootScale = llGetScale();&lt;br /&gt;
        if(llGetInventoryType(&amp;quot;OPA Notecard Import - 2011-11-03&amp;quot;) == INVENTORY_SCRIPT){&lt;br /&gt;
            llResetOtherScript(&amp;quot;OPA Notecard Import - 2011-11-03&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
/*    //Feel free to remove this on-touch trigger if you are using your own script to control playback&lt;br /&gt;
    touch_start(integer num_detected)&lt;br /&gt;
    {&lt;br /&gt;
        //only activate after publish.&lt;br /&gt;
        if (commandListenerHandle == -1)&lt;br /&gt;
        {&lt;br /&gt;
            //if animation not playing start it, else stop it.&lt;br /&gt;
            if( playAnimationStyle == 0)&lt;br /&gt;
                playAnimation(1.0,TRUE);&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                playAnimationStyle = 0;&lt;br /&gt;
                llSetTimerEvent(0);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }*/&lt;br /&gt;
 &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        //this is needed to detect scale changes and record the differences in order to adjust the animation accordingly.&lt;br /&gt;
        if (change &amp;amp; CHANGED_SCALE)&lt;br /&gt;
        {&lt;br /&gt;
            calc_scaleChange();&lt;br /&gt;
        }&lt;br /&gt;
        // if new prims are added or removed from this object then the script resets&lt;br /&gt;
        // because the animations are now broken.&lt;br /&gt;
        else if (change &amp;amp; CHANGED_LINK)&lt;br /&gt;
        {&lt;br /&gt;
            if( primCount != llGetNumberOfPrims() )&lt;br /&gt;
            {&lt;br /&gt;
                llOwnerSay(&amp;quot;Link change detected, reseting script.&amp;quot;);&lt;br /&gt;
                llResetScript();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    //The message link function is to allow other scripts to control the snapshot playback&lt;br /&gt;
    //This command will display snapshot #2:&lt;br /&gt;
    //      llMessageLinked(LINK_ROOT, 2, &amp;quot;XDshow&amp;quot;, NULL_KEY);  llSleep(1.0);&lt;br /&gt;
    //&lt;br /&gt;
    //This command will play through all the recorded snapshots in ascending order.  The number &amp;quot;1.0&amp;quot; is the delay speed and can be changed.&lt;br /&gt;
    //      llMessageLinked(LINK_ROOT, 0, &amp;quot;XDplay&amp;quot;, &amp;quot;1.0&amp;quot;);&lt;br /&gt;
    //&lt;br /&gt;
    //This command will loop through all the recorded snapshots in ascending order.  The number &amp;quot;1.0&amp;quot; is the delay speed and can be changed.&lt;br /&gt;
    //      llMessageLinked(LINK_ROOT, 0, &amp;quot;XDplayLoop&amp;quot;, &amp;quot;1.0&amp;quot;);&lt;br /&gt;
    //&lt;br /&gt;
    //To stop any playing animation use&lt;br /&gt;
    //      llMessageLinked(LINK_ROOT, 0, &amp;quot;XDstop&amp;quot;, NULL_KEY);&lt;br /&gt;
    link_message(integer sender_num, integer num, string str, key id)&lt;br /&gt;
    {&lt;br /&gt;
        if (&amp;quot;XDshow&amp;quot; == str &amp;amp;&amp;amp; num &amp;gt;= 1 &amp;amp;&amp;amp; num &amp;lt;= recordedSnapshots){&lt;br /&gt;
            showSnapshot(num);&lt;br /&gt;
        }else if (&amp;quot;XDplay&amp;quot; == str){&lt;br /&gt;
            currentSnapshot = 1;&lt;br /&gt;
            float delay = (float)((string)id);&lt;br /&gt;
            playAnimation(delay,FALSE);&lt;br /&gt;
        }else if (&amp;quot;XDplayLoop&amp;quot; == str){&lt;br /&gt;
            float delay = (float)((string)id);&lt;br /&gt;
            playAnimation(delay,TRUE);&lt;br /&gt;
        }else if (&amp;quot;XDstop&amp;quot; == str){&lt;br /&gt;
            playAnimationStyle = 0;&lt;br /&gt;
            llSetTimerEvent(0);&lt;br /&gt;
        }else if(&amp;quot;XDexport&amp;quot; == str &amp;amp;&amp;amp; num == 0){ // added by Marv&lt;br /&gt;
            list export = [];&lt;br /&gt;
            string foo;&lt;br /&gt;
            vector bar;&lt;br /&gt;
            rotation baa;&lt;br /&gt;
            string baz;&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j = primCount;&lt;br /&gt;
            for(i=2;i&amp;lt;=j;++i){&lt;br /&gt;
                export += [llGetLinkName(i)];&lt;br /&gt;
            }&lt;br /&gt;
            j= llGetListLength(posList);&lt;br /&gt;
            llMessageLinked(sender_num, 1, llDumpList2String(export,&amp;quot;|&amp;quot;)  , op_export);&lt;br /&gt;
            export = [];&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                bar = llList2Vector(posList,i);&lt;br /&gt;
                export += [&amp;quot;&amp;lt;&amp;quot; + truncate_float(bar.x) + &amp;quot;,&amp;quot; + truncate_float(bar.y) + &amp;quot;,&amp;quot; + truncate_float(bar.z) + &amp;quot;&amp;gt;&amp;quot;];&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(sender_num, 2, llDumpList2String(export,&amp;quot;|&amp;quot;)  , op_export);&lt;br /&gt;
            export = [];&lt;br /&gt;
            j= llGetListLength(rotList);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                baa = llList2Rot(rotList,i);&lt;br /&gt;
                export += [&amp;quot;&amp;lt;&amp;quot; + truncate_float(baa.x) + &amp;quot;,&amp;quot; + truncate_float(baa.y) + &amp;quot;,&amp;quot; + truncate_float(baa.z) + &amp;quot;,&amp;quot; + truncate_float(baa.s) + &amp;quot;&amp;gt;&amp;quot;];&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(sender_num, 3, llDumpList2String(export,&amp;quot;|&amp;quot;)  , op_export);&lt;br /&gt;
            export = [];&lt;br /&gt;
            j= llGetListLength(scaleList);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                bar = llList2Vector(scaleList,i);&lt;br /&gt;
                export += [&amp;quot;&amp;lt;&amp;quot; + truncate_float(bar.x) + &amp;quot;,&amp;quot; + truncate_float(bar.y) + &amp;quot;,&amp;quot; + truncate_float(bar.z) + &amp;quot;&amp;gt;&amp;quot;];&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(sender_num, 4, llDumpList2String(export,&amp;quot;|&amp;quot;)  , op_export);&lt;br /&gt;
        }else if(&amp;quot;XDmenu&amp;quot; == str){&lt;br /&gt;
            showMenuDialog();&lt;br /&gt;
        }else if(&amp;quot;XDimportLength&amp;quot; == str &amp;amp;&amp;amp; num &amp;gt; 0){&lt;br /&gt;
            list foo = [];&lt;br /&gt;
            list bar = [];&lt;br /&gt;
            integer i;&lt;br /&gt;
            for(i=0;i&amp;lt;num;++i){&lt;br /&gt;
                foo += [ZERO_VECTOR];&lt;br /&gt;
                bar += [ZERO_ROTATION];&lt;br /&gt;
            }&lt;br /&gt;
            posList = foo;&lt;br /&gt;
            scaleList = foo;&lt;br /&gt;
            rotList = bar;&lt;br /&gt;
            llMessageLinked(sender_num,-1,str,op_import);&lt;br /&gt;
            recordedSnapshots = num / (llGetNumberOfPrims() - 1);&lt;br /&gt;
            llMessageLinked(LINK_SET, recordedSnapshots, &amp;quot;XDrecordedSnapshots&amp;quot;, NULL_KEY);&lt;br /&gt;
            currentSnapshot = 1;&lt;br /&gt;
        }else if(&amp;quot;XDrecordedSnapshots&amp;quot; == str &amp;amp;&amp;amp; num == -1){&lt;br /&gt;
            llMessageLinked(sender_num,recordedSnapshots,str,NULL_KEY);&lt;br /&gt;
        }else if(id == op_import &amp;amp;&amp;amp; num &amp;gt;= 0){&lt;br /&gt;
            list params = llParseString2List(str, [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
            vector impPos = (vector)llList2String(params,0);&lt;br /&gt;
            rotation impRot = (rotation)llList2String(params,1);&lt;br /&gt;
            vector impSize  = (vector)llList2String(params,2);&lt;br /&gt;
            posList = llListReplaceList(posList,[impPos],num,num);&lt;br /&gt;
            rotList = llListReplaceList(rotList,[impRot],num,num);&lt;br /&gt;
            scaleList = llListReplaceList(scaleList,[impSize],num,num);&lt;br /&gt;
        }else if(id == op_alter_rootScale){&lt;br /&gt;
            rootScale = (vector)str;&lt;br /&gt;
            calc_scaleChange();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    //This event handler takes care of all the editing commands.&lt;br /&gt;
    //Available commands are: record, play, publish, show next, show prev, show #&lt;br /&gt;
    listen(integer channel, string name, key id, string message)&lt;br /&gt;
    {&lt;br /&gt;
        list parsedMessage = llParseString2List(message, [&amp;quot; &amp;quot;], []);&lt;br /&gt;
        string firstWord = llToLower(llList2String(parsedMessage,0));&lt;br /&gt;
        string secondWord = llToLower(llList2String(parsedMessage,1));&lt;br /&gt;
 &lt;br /&gt;
        //display a snapshot&lt;br /&gt;
        if(&amp;quot;show&amp;quot; == firstWord &amp;amp;&amp;amp; recordedSnapshots &amp;gt; 0)&lt;br /&gt;
        {&lt;br /&gt;
            //stop any currently playing animation.&lt;br /&gt;
            llSetTimerEvent(0);&lt;br /&gt;
 &lt;br /&gt;
            if(secondWord == &amp;quot;next&amp;quot;)&lt;br /&gt;
            {&lt;br /&gt;
                currentSnapshot++;&lt;br /&gt;
                if(currentSnapshot &amp;gt; recordedSnapshots)&lt;br /&gt;
                    currentSnapshot = 1;&lt;br /&gt;
 &lt;br /&gt;
                showSnapshot(currentSnapshot);&lt;br /&gt;
            }&lt;br /&gt;
            else if(secondWord == &amp;quot;prev&amp;quot;)&lt;br /&gt;
            {&lt;br /&gt;
                currentSnapshot--;&lt;br /&gt;
                if(currentSnapshot &amp;lt; 1)&lt;br /&gt;
                    currentSnapshot = recordedSnapshots;&lt;br /&gt;
 &lt;br /&gt;
                showSnapshot(currentSnapshot);&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                // when the conversion fails, snapshotNumber = 0&lt;br /&gt;
                currentSnapshot = (integer)secondWord;&lt;br /&gt;
                if(currentSnapshot &amp;gt; 0 &amp;amp;&amp;amp; currentSnapshot &amp;lt;= recordedSnapshots )&lt;br /&gt;
                {&lt;br /&gt;
                    showSnapshot(currentSnapshot);&lt;br /&gt;
                    llOwnerSay(&amp;quot;Showing snapshot: &amp;quot;+(string)currentSnapshot);&lt;br /&gt;
                }&lt;br /&gt;
                else&lt;br /&gt;
                {&lt;br /&gt;
                    llOwnerSay(&amp;quot;Invalid snapshot number given: &amp;quot; + (string) currentSnapshot +&lt;br /&gt;
                                &amp;quot;\nA valid snapshot number is between 1 and &amp;quot; + (string) recordedSnapshots);&lt;br /&gt;
                    currentSnapshot = 1;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //record a snapshot&lt;br /&gt;
        else if(firstWord == &amp;quot;record&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            integer i = 0;&lt;br /&gt;
            //2 is the first linked prim number.&lt;br /&gt;
            vector rootPos = llGetPos();&lt;br /&gt;
            for( i = 2; i &amp;lt;= primCount; i++)&lt;br /&gt;
            {&lt;br /&gt;
                vector pos = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_POSITION]),0);&lt;br /&gt;
                //need to convert into local position&lt;br /&gt;
                pos.x -= rootPos.x;&lt;br /&gt;
                pos.z -= rootPos.z;&lt;br /&gt;
                pos.y -= rootPos.y;&lt;br /&gt;
                pos = pos / llGetRot();&lt;br /&gt;
                posList += pos;&lt;br /&gt;
 &lt;br /&gt;
                rotation rot = llList2Rot(llGetLinkPrimitiveParams(i, [PRIM_ROTATION]),0);&lt;br /&gt;
                //Converting into local rot&lt;br /&gt;
                rot = rot / llGetRot();&lt;br /&gt;
                rotList += rot;&lt;br /&gt;
 &lt;br /&gt;
                scaleList += llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]),0);&lt;br /&gt;
            }&lt;br /&gt;
            recordedSnapshots++;&lt;br /&gt;
 &lt;br /&gt;
            llOwnerSay(&amp;quot;Total number of snapshots recorded: &amp;quot; + (string)recordedSnapshots);&lt;br /&gt;
            freeMemory = llGetFreeMemory();&lt;br /&gt;
        }&lt;br /&gt;
        //play the animation from beginning to end once without looping.&lt;br /&gt;
        else if (firstWord == &amp;quot;play&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            float delay = (float)secondWord;&lt;br /&gt;
            currentSnapshot = 1;&lt;br /&gt;
            //play the animation once without loop&lt;br /&gt;
            playAnimation(delay, FALSE);&lt;br /&gt;
        }&lt;br /&gt;
        //publish disables the recording features and enables the on-touch trigger&lt;br /&gt;
        else if(&amp;quot;publish&amp;quot; == firstWord)&lt;br /&gt;
        {&lt;br /&gt;
            //stop any currently playing animation.&lt;br /&gt;
            llSetTimerEvent(0);&lt;br /&gt;
            playAnimationStyle = 0;&lt;br /&gt;
            currentSnapshot = 1;&lt;br /&gt;
 &lt;br /&gt;
            //remove listeners to disable recording&lt;br /&gt;
            llListenRemove(commandListenerHandle);&lt;br /&gt;
            commandListenerHandle = -1; //indicating that it&#039;s been published&lt;br /&gt;
 &lt;br /&gt;
            llOwnerSay(&amp;quot;Recording disabled. Publish complete.\nClick me to toggle animation on/off.&amp;quot;);&lt;br /&gt;
        }else if(&amp;quot;loop&amp;quot; == firstWord){&lt;br /&gt;
            llMessageLinked(LINK_THIS,0,&amp;quot;XDplayLoop&amp;quot;,NULL_KEY);&lt;br /&gt;
        }else if(&amp;quot;stop&amp;quot; == firstWord){&lt;br /&gt;
            llMessageLinked(LINK_THIS,0,&amp;quot;XDstop&amp;quot;,NULL_KEY);&lt;br /&gt;
        }else if(&amp;quot;export&amp;quot; == firstWord){&lt;br /&gt;
            llOwnerSay(&amp;quot;Should be exporting&amp;quot;);&lt;br /&gt;
            llMessageLinked(LINK_THIS,0,&amp;quot;XDexport&amp;quot;,NULL_KEY);&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        //if not published, show menu&lt;br /&gt;
        if(commandListenerHandle != -1)&lt;br /&gt;
            showMenuDialog();&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    //Timer event is used to handle the animation playback.&lt;br /&gt;
    timer()&lt;br /&gt;
    {&lt;br /&gt;
        showSnapshot(currentSnapshot);&lt;br /&gt;
 &lt;br /&gt;
        //if not at the end of the animation, increment the counter&lt;br /&gt;
        if(currentSnapshot &amp;lt; recordedSnapshots)&lt;br /&gt;
            currentSnapshot++;&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            // if animation is looping, set the counter back to 1&lt;br /&gt;
            if( playAnimationStyle == 2)&lt;br /&gt;
                currentSnapshot = 1;&lt;br /&gt;
            // if animation isn&#039;t looping, stop the animation&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                llSetTimerEvent(0);&lt;br /&gt;
                //if not published, show dialog menu&lt;br /&gt;
                if(commandListenerHandle != -1)&lt;br /&gt;
                    showMenuDialog();&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;
[[Category:Open Prim Animator|Open Prim Animator]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Import-Export&amp;diff=1159599</id>
		<title>Open Prim Animator/Import-Export</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Import-Export&amp;diff=1159599"/>
		<updated>2011-12-14T11:15:42Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: whoops, meant to make the commit sans-incomplete docs :D&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
//!  @brief Animation export script for [[Open Prim Animator]] http://wiki.secondlife.com/wiki/Open_Prim_Animator&lt;br /&gt;
/**&lt;br /&gt;
*    @author [[User:SignpostMarv Martin|SignpostMarv]]&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
//!  Storing the names in exports allows us to remap links according to their current state&lt;br /&gt;
/**&lt;br /&gt;
*    we want to store the names because there are circumstances where the link order can change-&lt;br /&gt;
*      TPV object import/export&lt;br /&gt;
*      accidentally delinking objects etc.&lt;br /&gt;
*    Once an import has been parsed, the script checks it against &lt;br /&gt;
*/&lt;br /&gt;
list names;&lt;br /&gt;
list pos;&lt;br /&gt;
list rot;&lt;br /&gt;
list size;&lt;br /&gt;
&lt;br /&gt;
key import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
key export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s = 249;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(&amp;quot;\n&amp;quot; + llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(&amp;quot;\n&amp;quot; + _export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string truncate_float(float foo){&lt;br /&gt;
    if(foo == 0.0){&lt;br /&gt;
        return &amp;quot;0&amp;quot;;&lt;br /&gt;
    }else if(foo == (float)((integer)foo)){&lt;br /&gt;
        return (string)((integer)foo);&lt;br /&gt;
    }&lt;br /&gt;
    string bar = (string)foo;&lt;br /&gt;
    while(llGetSubString(bar,-1,-1) == &amp;quot;0&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);   &lt;br /&gt;
    }&lt;br /&gt;
    if(llGetSubString(bar,-1,-1) == &amp;quot;.&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);&lt;br /&gt;
    }&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string truncate_vector(vector foo){&lt;br /&gt;
    if(foo == ZERO_VECTOR){&lt;br /&gt;
        return &amp;quot;&amp;lt;0,0,0&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    string bar = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.x) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.y) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.z) + &amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string truncate_rotation(rotation foo){&lt;br /&gt;
    if(foo == ZERO_ROTATION){&lt;br /&gt;
        return &amp;quot;&amp;lt;0,0,0,1&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    string bar = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.x) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.y) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.z) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.s) + &amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    link_message(integer s, integer n, string m, key k){&lt;br /&gt;
        if(k == export){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j;&lt;br /&gt;
            if(n == 1){&lt;br /&gt;
                names = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
            }else if(n == 2){&lt;br /&gt;
                pos   = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(pos);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    pos = llListReplaceList(pos,[(vector)llList2String(pos,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }else if(n == 3){&lt;br /&gt;
                rot   = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(rot);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    rot = llListReplaceList(rot,[(rotation)llList2String(rot,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }else if(n == 4){&lt;br /&gt;
                size  = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(size);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    size = llListReplaceList(size,[(vector)llList2String(size,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            if(names != [] &amp;amp;&amp;amp; pos != [] &amp;amp;&amp;amp; rot != [] &amp;amp;&amp;amp; size != []){&lt;br /&gt;
&lt;br /&gt;
                llOwnerSay(&amp;quot;Exporting:&amp;quot;);&lt;br /&gt;
                export_string(&amp;quot;rootscale:&amp;quot; + truncate_vector(llGetScale()));&lt;br /&gt;
                export_string(&amp;quot;names:&amp;quot; + llDumpList2String(names,&amp;quot;|&amp;quot;));&lt;br /&gt;
                &lt;br /&gt;
                list bar = [];&lt;br /&gt;
                j= llGetListLength(pos);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_vector(llList2Vector(pos,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;pos:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_rotation(llList2Rot(rot,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;rot:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_vector(llList2Vector(size,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;size:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);&lt;br /&gt;
                llResetScript();&lt;br /&gt;
            }&lt;br /&gt;
        }else if(k == import &amp;amp;&amp;amp; n == -1){&lt;br /&gt;
            llOwnerSay(&amp;quot;importing&amp;quot;);&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j=llGetListLength(pos);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                llMessageLinked(s,i,llDumpList2String([llList2Vector(pos,i),llList2Rot(rot,i),llList2Vector(size,i)],&amp;quot;|&amp;quot;),import);&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);&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;
[[Category:Open Prim Animator]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Import-Export&amp;diff=1159598</id>
		<title>Open Prim Animator/Import-Export</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator/Import-Export&amp;diff=1159598"/>
		<updated>2011-12-14T11:15:11Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: Uploading the import/export script&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
//!  @brief Animation export script for [[Open Prim Animator]] http://wiki.secondlife.com/wiki/Open_Prim_Animator&lt;br /&gt;
/**&lt;br /&gt;
*    @author [[User:SignpostMarv Martin|SignpostMarv]]&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
//!  Storing the names in exports allows us to remap links according to their current state&lt;br /&gt;
/**&lt;br /&gt;
*    we want to store the names because there are circumstances where the link order can change-&lt;br /&gt;
*      TPV object import/export&lt;br /&gt;
*      accidentally delinking objects etc.&lt;br /&gt;
*    Once an import has been parsed, the script checks it against &lt;br /&gt;
list names;&lt;br /&gt;
list pos;&lt;br /&gt;
list rot;&lt;br /&gt;
list size;&lt;br /&gt;
&lt;br /&gt;
key import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
key export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
export_string(string _export_string){&lt;br /&gt;
    integer s = 249;&lt;br /&gt;
    while(llStringLength(_export_string) &amp;gt; s){&lt;br /&gt;
        llOwnerSay(&amp;quot;\n&amp;quot; + llGetSubString(_export_string,0,(s-1)));&lt;br /&gt;
        _export_string = llGetSubString(_export_string,s,-1);&lt;br /&gt;
    }&lt;br /&gt;
    if(llStringLength(_export_string) &amp;gt; 0){&lt;br /&gt;
        llOwnerSay(&amp;quot;\n&amp;quot; + _export_string);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string truncate_float(float foo){&lt;br /&gt;
    if(foo == 0.0){&lt;br /&gt;
        return &amp;quot;0&amp;quot;;&lt;br /&gt;
    }else if(foo == (float)((integer)foo)){&lt;br /&gt;
        return (string)((integer)foo);&lt;br /&gt;
    }&lt;br /&gt;
    string bar = (string)foo;&lt;br /&gt;
    while(llGetSubString(bar,-1,-1) == &amp;quot;0&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);   &lt;br /&gt;
    }&lt;br /&gt;
    if(llGetSubString(bar,-1,-1) == &amp;quot;.&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);&lt;br /&gt;
    }&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string truncate_vector(vector foo){&lt;br /&gt;
    if(foo == ZERO_VECTOR){&lt;br /&gt;
        return &amp;quot;&amp;lt;0,0,0&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    string bar = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.x) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.y) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.z) + &amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string truncate_rotation(rotation foo){&lt;br /&gt;
    if(foo == ZERO_ROTATION){&lt;br /&gt;
        return &amp;quot;&amp;lt;0,0,0,1&amp;gt;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    string bar = &amp;quot;&amp;lt;&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.x) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.y) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.z) + &amp;quot;,&amp;quot;;&lt;br /&gt;
    bar += truncate_float(foo.s) + &amp;quot;&amp;gt;&amp;quot;;&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default{&lt;br /&gt;
    link_message(integer s, integer n, string m, key k){&lt;br /&gt;
        if(k == export){&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j;&lt;br /&gt;
            if(n == 1){&lt;br /&gt;
                names = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
            }else if(n == 2){&lt;br /&gt;
                pos   = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(pos);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    pos = llListReplaceList(pos,[(vector)llList2String(pos,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }else if(n == 3){&lt;br /&gt;
                rot   = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(rot);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    rot = llListReplaceList(rot,[(rotation)llList2String(rot,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }else if(n == 4){&lt;br /&gt;
                size  = llParseString2List(m,[&amp;quot;|&amp;quot;],[]);&lt;br /&gt;
                j=llGetListLength(size);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    size = llListReplaceList(size,[(vector)llList2String(size,i)],i,i);&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            if(names != [] &amp;amp;&amp;amp; pos != [] &amp;amp;&amp;amp; rot != [] &amp;amp;&amp;amp; size != []){&lt;br /&gt;
&lt;br /&gt;
                llOwnerSay(&amp;quot;Exporting:&amp;quot;);&lt;br /&gt;
                export_string(&amp;quot;rootscale:&amp;quot; + truncate_vector(llGetScale()));&lt;br /&gt;
                export_string(&amp;quot;names:&amp;quot; + llDumpList2String(names,&amp;quot;|&amp;quot;));&lt;br /&gt;
                &lt;br /&gt;
                list bar = [];&lt;br /&gt;
                j= llGetListLength(pos);&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_vector(llList2Vector(pos,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;pos:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_rotation(llList2Rot(rot,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;rot:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                    bar += truncate_vector(llList2Vector(size,i));&lt;br /&gt;
                }&lt;br /&gt;
                export_string(&amp;quot;size:&amp;quot; + llDumpList2String(bar,&amp;quot;|&amp;quot;));&lt;br /&gt;
                bar = [];&lt;br /&gt;
                llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);&lt;br /&gt;
                llResetScript();&lt;br /&gt;
            }&lt;br /&gt;
        }else if(k == import &amp;amp;&amp;amp; n == -1){&lt;br /&gt;
            llOwnerSay(&amp;quot;importing&amp;quot;);&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j=llGetListLength(pos);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                llMessageLinked(s,i,llDumpList2String([llList2Vector(pos,i),llList2Rot(rot,i),llList2Vector(size,i)],&amp;quot;|&amp;quot;),import);&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(LINK_THIS,0,&amp;quot;XDmenu&amp;quot;,NULL_KEY);&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;
[[Category:Open Prim Animator]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator&amp;diff=1159597</id>
		<title>Open Prim Animator</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Open_Prim_Animator&amp;diff=1159597"/>
		<updated>2011-12-14T11:06:30Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: Committing changes made to OPA made over the past year at work&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
// Open Prim Animator - by Todd Borst&lt;br /&gt;
// Extensive Modifications by SignpostMarv Martin&lt;br /&gt;
 &lt;br /&gt;
// This is provided AS IS without support.  Please don&#039;t bug me demanding &lt;br /&gt;
// help or custom work for this free script.&lt;br /&gt;
 &lt;br /&gt;
// Summary: This is a simple prim animation script.  Just add this script&lt;br /&gt;
// to your object and a dialog will automatically pop up for you to use.&lt;br /&gt;
 &lt;br /&gt;
// Features:&lt;br /&gt;
// -Single script &amp;quot;Prim Puppeteer&amp;quot; like animation tool&lt;br /&gt;
// -Playback controllable through external scripts&lt;br /&gt;
// -Animation is scalable and resizeable&lt;br /&gt;
// -On-touch trigger built-in&lt;br /&gt;
// -Completely free and open sourced &lt;br /&gt;
 &lt;br /&gt;
// License:&lt;br /&gt;
// You are welcome to use this anyway you like, even bring to other grids&lt;br /&gt;
// outside of Second Life.  If you try to sell what I&#039;m giving away for&lt;br /&gt;
// free, you will be cursed with unimaginably bad juju.&lt;br /&gt;
 &lt;br /&gt;
integer COMMAND_CHANNEL = 32;&lt;br /&gt;
 &lt;br /&gt;
integer primCount = 0;&lt;br /&gt;
integer commandListenerHandle = -1;&lt;br /&gt;
 &lt;br /&gt;
list posList     = [];&lt;br /&gt;
list rotList     = [];&lt;br /&gt;
list scaleList   = [];&lt;br /&gt;
integer currentSnapshot   = 0;&lt;br /&gt;
integer recordedSnapshots = 0;&lt;br /&gt;
 &lt;br /&gt;
vector rootScale   = ZERO_VECTOR;&lt;br /&gt;
vector scaleChange = &amp;lt;1,1,1&amp;gt;;&lt;br /&gt;
 &lt;br /&gt;
// For tracking memory usage.  The amount of snapshots you can record is based&lt;br /&gt;
// on the number of prims and available memory.  Less prims = more snapshots&lt;br /&gt;
integer maxMemory  = 0;&lt;br /&gt;
integer freeMemory = 0;&lt;br /&gt;
 &lt;br /&gt;
integer playAnimationStyle = 0;&lt;br /&gt;
// The values for playAnimationStyle means&lt;br /&gt;
// 0 = no animation playing&lt;br /&gt;
// 1 = play animation once&lt;br /&gt;
// 2 = play animation looping&lt;br /&gt;
 &lt;br /&gt;
// This function is used to display a recorded snapshot&lt;br /&gt;
showSnapshot(integer snapNumber)&lt;br /&gt;
{&lt;br /&gt;
    if(snapNumber &amp;gt; 0 &amp;amp;&amp;amp; snapNumber &amp;lt;= recordedSnapshots )&lt;br /&gt;
    {&lt;br /&gt;
        integer i = 0;&lt;br /&gt;
        vector   pos;&lt;br /&gt;
        rotation rot;&lt;br /&gt;
        vector   scale;&lt;br /&gt;
 &lt;br /&gt;
        vector rootPos = llGetPos();&lt;br /&gt;
 &lt;br /&gt;
        // Might want to move llGetRot() into the loop for fast rotating objects.&lt;br /&gt;
        // Rotation during the animation playback may cause errors.&lt;br /&gt;
        rotation rootRot = llGetRot();&lt;br /&gt;
&lt;br /&gt;
        list params = [];&lt;br /&gt;
 &lt;br /&gt;
        //2 is the first linked prim number.&lt;br /&gt;
        for( i = 2; i &amp;lt;= primCount; i++)&lt;br /&gt;
        {&lt;br /&gt;
            pos     = llList2Vector(posList,((snapNumber-1)*(primCount-1))+(i-2));&lt;br /&gt;
            rot     = llList2Rot(rotList,((snapNumber-1)*(primCount-1))+(i-2));&lt;br /&gt;
            scale   = llList2Vector(scaleList,((snapNumber-1)*(primCount-1))+(i-2));&lt;br /&gt;
 &lt;br /&gt;
            //Adjust for scale changes&lt;br /&gt;
            if( rootScale.x != 1.0 || rootScale.y != 1.0 || rootScale.z != 1.0 )&lt;br /&gt;
            {&lt;br /&gt;
                pos.x *= scaleChange.x;&lt;br /&gt;
                pos.y *= scaleChange.y;&lt;br /&gt;
                pos.z *= scaleChange.z;&lt;br /&gt;
                scale.x *= scaleChange.x;&lt;br /&gt;
                scale.y *= scaleChange.y;&lt;br /&gt;
                scale.z *= scaleChange.z;&lt;br /&gt;
            }&lt;br /&gt;
            params += [&lt;br /&gt;
                PRIM_LINK_TARGET,&lt;br /&gt;
                    i,&lt;br /&gt;
                PRIM_POSITION,&lt;br /&gt;
                    pos,&lt;br /&gt;
                PRIM_ROTATION,&lt;br /&gt;
                    rot/rootRot,&lt;br /&gt;
                PRIM_SIZE,&lt;br /&gt;
                    scale&lt;br /&gt;
            ];&lt;br /&gt;
 &lt;br /&gt;
            if(llGetListLength(params) &amp;gt; 64){&lt;br /&gt;
                llSetLinkPrimitiveParamsFast(LINK_THIS,params);&lt;br /&gt;
                params = [];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        if(llGetListLength(params) &amp;gt; 0){&lt;br /&gt;
            llSetLinkPrimitiveParamsFast(LINK_THIS,params);&lt;br /&gt;
            params = [];&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// This function is used to start a sequential animation playback.&lt;br /&gt;
// If the delay speed is set too low, the script might not be able to keep up.&lt;br /&gt;
playAnimation(float delay, integer loop)&lt;br /&gt;
{&lt;br /&gt;
    if(delay &amp;lt; 0.1) delay = 1.0;&lt;br /&gt;
 &lt;br /&gt;
    if( loop == FALSE)&lt;br /&gt;
        playAnimationStyle = 1;&lt;br /&gt;
    else&lt;br /&gt;
        playAnimationStyle = 2;&lt;br /&gt;
 &lt;br /&gt;
    if (recordedSnapshots &amp;gt;= 1)&lt;br /&gt;
        llSetTimerEvent(delay);&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
// This shows the edit menu&lt;br /&gt;
showMenuDialog()&lt;br /&gt;
{&lt;br /&gt;
    return; // comment out line to re-enable menu&lt;br /&gt;
    string temp = (string)((float)freeMemory/(float)maxMemory * 100.0);&lt;br /&gt;
    string menuText = &amp;quot;Available Memory: &amp;quot; + (string)freeMemory + &amp;quot; (&amp;quot; + llGetSubString(temp, 0, 4) +&amp;quot;%)&amp;quot; +&lt;br /&gt;
    &amp;quot;\nCurrent Snapshot: &amp;quot; + (string)currentSnapshot +&amp;quot;\tSnapshots Recorded: &amp;quot; + (string)recordedSnapshots +&lt;br /&gt;
    &amp;quot;\n\n[ Record ] - Record a snapshot of prim positions\n[ Play ] - Play back all the recorded snapshots\n[ Publish ] - Finish the recording process\n[ Show Next ] - Show the next snapshot\n[ Show Prev ] - Show the previous snapshot&amp;quot;;&lt;br /&gt;
 &lt;br /&gt;
    llDialog(llGetOwner(), menuText, [&amp;quot;Record&amp;quot;,&amp;quot;Play&amp;quot;,&amp;quot;Publish&amp;quot;,&amp;quot;Show Prev&amp;quot;,&amp;quot;Show Next&amp;quot;,&amp;quot;Loop&amp;quot;,&amp;quot;Stop&amp;quot;,&amp;quot;Export&amp;quot;], COMMAND_CHANNEL);&lt;br /&gt;
}&lt;br /&gt;
string truncate_float(float foo){&lt;br /&gt;
    if(foo == 0.0){&lt;br /&gt;
        return &amp;quot;0&amp;quot;;&lt;br /&gt;
    }else if(foo == (float)((integer)foo)){&lt;br /&gt;
        return (string)((integer)foo);&lt;br /&gt;
    }&lt;br /&gt;
    string bar = (string)foo;&lt;br /&gt;
    while(llGetSubString(bar,-1,-1) == &amp;quot;0&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);   &lt;br /&gt;
    }&lt;br /&gt;
    if(llGetSubString(bar,-1,-1) == &amp;quot;.&amp;quot;){&lt;br /&gt;
        bar = llGetSubString(bar,0,-2);&lt;br /&gt;
    }&lt;br /&gt;
    return bar;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
key op_import = &amp;quot;6b78fcc8-e147-4105-99a6-ff19b4bf559d&amp;quot;;&lt;br /&gt;
key op_export = &amp;quot;7c2ca168-2b64-4836-8727-8e62b78dbd44&amp;quot;;&lt;br /&gt;
key op_alter_rootScale = &amp;quot;f9d3389e-a78c-43f8-9e35-c11adec112a5&amp;quot;;&lt;br /&gt;
calc_scaleChange(){&lt;br /&gt;
    if (rootScale != ZERO_VECTOR){&lt;br /&gt;
        vector newScale = llGetScale();&lt;br /&gt;
        //since change_scale is triggered even with linked prim changes,&lt;br /&gt;
        //this is to filter out non-root changes.&lt;br /&gt;
        if( ( newScale.x / rootScale.x) != scaleChange.x ||&lt;br /&gt;
            ( newScale.y / rootScale.y) != scaleChange.y ||&lt;br /&gt;
            ( newScale.z / rootScale.z) != scaleChange.z )&lt;br /&gt;
        {&lt;br /&gt;
            scaleChange.x = newScale.x / rootScale.x;&lt;br /&gt;
            scaleChange.y = newScale.y / rootScale.y;&lt;br /&gt;
            scaleChange.z = newScale.z / rootScale.z;&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;
        maxMemory = llGetFreeMemory();&lt;br /&gt;
        freeMemory = llGetFreeMemory();&lt;br /&gt;
 &lt;br /&gt;
        primCount = llGetNumberOfPrims();&lt;br /&gt;
        commandListenerHandle = llListen(COMMAND_CHANNEL,&amp;quot;&amp;quot;, llGetOwner(), &amp;quot;&amp;quot;);&lt;br /&gt;
        showMenuDialog();&lt;br /&gt;
 &lt;br /&gt;
        //setting initial root scale.  this allows the animation to scale if the root size is changed afterwards.&lt;br /&gt;
        rootScale = llGetScale();&lt;br /&gt;
        if(llGetInventoryType(&amp;quot;OPA Notecard Import - 2011-11-03&amp;quot;) == INVENTORY_SCRIPT){&lt;br /&gt;
            llResetOtherScript(&amp;quot;OPA Notecard Import - 2011-11-03&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
/*    //Feel free to remove this on-touch trigger if you are using your own script to control playback&lt;br /&gt;
    touch_start(integer num_detected)&lt;br /&gt;
    {&lt;br /&gt;
        //only activate after publish.&lt;br /&gt;
        if (commandListenerHandle == -1)&lt;br /&gt;
        {&lt;br /&gt;
            //if animation not playing start it, else stop it.&lt;br /&gt;
            if( playAnimationStyle == 0)&lt;br /&gt;
                playAnimation(1.0,TRUE);&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                playAnimationStyle = 0;&lt;br /&gt;
                llSetTimerEvent(0);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }*/&lt;br /&gt;
 &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        //this is needed to detect scale changes and record the differences in order to adjust the animation accordingly.&lt;br /&gt;
        if (change &amp;amp; CHANGED_SCALE)&lt;br /&gt;
        {&lt;br /&gt;
            calc_scaleChange();&lt;br /&gt;
        }&lt;br /&gt;
        // if new prims are added or removed from this object then the script resets&lt;br /&gt;
        // because the animations are now broken.&lt;br /&gt;
        else if (change &amp;amp; CHANGED_LINK)&lt;br /&gt;
        {&lt;br /&gt;
            if( primCount != llGetNumberOfPrims() )&lt;br /&gt;
            {&lt;br /&gt;
                llOwnerSay(&amp;quot;Link change detected, reseting script.&amp;quot;);&lt;br /&gt;
                llResetScript();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    //The message link function is to allow other scripts to control the snapshot playback&lt;br /&gt;
    //This command will display snapshot #2:&lt;br /&gt;
    //      llMessageLinked(LINK_ROOT, 2, &amp;quot;XDshow&amp;quot;, NULL_KEY);  llSleep(1.0);&lt;br /&gt;
    //&lt;br /&gt;
    //This command will play through all the recorded snapshots in ascending order.  The number &amp;quot;1.0&amp;quot; is the delay speed and can be changed.&lt;br /&gt;
    //      llMessageLinked(LINK_ROOT, 0, &amp;quot;XDplay&amp;quot;, &amp;quot;1.0&amp;quot;);&lt;br /&gt;
    //&lt;br /&gt;
    //This command will loop through all the recorded snapshots in ascending order.  The number &amp;quot;1.0&amp;quot; is the delay speed and can be changed.&lt;br /&gt;
    //      llMessageLinked(LINK_ROOT, 0, &amp;quot;XDplayLoop&amp;quot;, &amp;quot;1.0&amp;quot;);&lt;br /&gt;
    //&lt;br /&gt;
    //To stop any playing animation use&lt;br /&gt;
    //      llMessageLinked(LINK_ROOT, 0, &amp;quot;XDstop&amp;quot;, NULL_KEY);&lt;br /&gt;
    link_message(integer sender_num, integer num, string str, key id)&lt;br /&gt;
    {&lt;br /&gt;
        if (&amp;quot;XDshow&amp;quot; == str &amp;amp;&amp;amp; num &amp;gt;= 1 &amp;amp;&amp;amp; num &amp;lt;= recordedSnapshots){&lt;br /&gt;
            showSnapshot(num);&lt;br /&gt;
        }else if (&amp;quot;XDplay&amp;quot; == str){&lt;br /&gt;
            currentSnapshot = 1;&lt;br /&gt;
            float delay = (float)((string)id);&lt;br /&gt;
            playAnimation(delay,FALSE);&lt;br /&gt;
        }else if (&amp;quot;XDplayLoop&amp;quot; == str){&lt;br /&gt;
            float delay = (float)((string)id);&lt;br /&gt;
            playAnimation(delay,TRUE);&lt;br /&gt;
        }else if (&amp;quot;XDstop&amp;quot; == str){&lt;br /&gt;
            playAnimationStyle = 0;&lt;br /&gt;
            llSetTimerEvent(0);&lt;br /&gt;
        }else if(&amp;quot;XDexport&amp;quot; == str &amp;amp;&amp;amp; num == 0){ // added by Marv&lt;br /&gt;
            list export = [];&lt;br /&gt;
            string foo;&lt;br /&gt;
            vector bar;&lt;br /&gt;
            rotation baa;&lt;br /&gt;
            string baz;&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer j = primCount;&lt;br /&gt;
            for(i=2;i&amp;lt;=j;++i){&lt;br /&gt;
                export += [llGetLinkName(i)];&lt;br /&gt;
            }&lt;br /&gt;
            j= llGetListLength(posList);&lt;br /&gt;
            llMessageLinked(sender_num, 1, llDumpList2String(export,&amp;quot;|&amp;quot;)  , op_export);&lt;br /&gt;
            export = [];&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                bar = llList2Vector(posList,i);&lt;br /&gt;
                export += [&amp;quot;&amp;lt;&amp;quot; + truncate_float(bar.x) + &amp;quot;,&amp;quot; + truncate_float(bar.y) + &amp;quot;,&amp;quot; + truncate_float(bar.z) + &amp;quot;&amp;gt;&amp;quot;];&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(sender_num, 2, llDumpList2String(export,&amp;quot;|&amp;quot;)  , op_export);&lt;br /&gt;
            export = [];&lt;br /&gt;
            j= llGetListLength(rotList);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                baa = llList2Rot(rotList,i);&lt;br /&gt;
                export += [&amp;quot;&amp;lt;&amp;quot; + truncate_float(baa.x) + &amp;quot;,&amp;quot; + truncate_float(baa.y) + &amp;quot;,&amp;quot; + truncate_float(baa.z) + &amp;quot;,&amp;quot; + truncate_float(baa.s) + &amp;quot;&amp;gt;&amp;quot;];&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(sender_num, 3, llDumpList2String(export,&amp;quot;|&amp;quot;)  , op_export);&lt;br /&gt;
            export = [];&lt;br /&gt;
            j= llGetListLength(scaleList);&lt;br /&gt;
            for(i=0;i&amp;lt;j;++i){&lt;br /&gt;
                bar = llList2Vector(scaleList,i);&lt;br /&gt;
                export += [&amp;quot;&amp;lt;&amp;quot; + truncate_float(bar.x) + &amp;quot;,&amp;quot; + truncate_float(bar.y) + &amp;quot;,&amp;quot; + truncate_float(bar.z) + &amp;quot;&amp;gt;&amp;quot;];&lt;br /&gt;
            }&lt;br /&gt;
            llMessageLinked(sender_num, 4, llDumpList2String(export,&amp;quot;|&amp;quot;)  , op_export);&lt;br /&gt;
        }else if(&amp;quot;XDmenu&amp;quot; == str){&lt;br /&gt;
            showMenuDialog();&lt;br /&gt;
        }else if(&amp;quot;XDimportLength&amp;quot; == str &amp;amp;&amp;amp; num &amp;gt; 0){&lt;br /&gt;
            list foo = [];&lt;br /&gt;
            list bar = [];&lt;br /&gt;
            integer i;&lt;br /&gt;
            for(i=0;i&amp;lt;num;++i){&lt;br /&gt;
                foo += [ZERO_VECTOR];&lt;br /&gt;
                bar += [ZERO_ROTATION];&lt;br /&gt;
            }&lt;br /&gt;
            posList = foo;&lt;br /&gt;
            scaleList = foo;&lt;br /&gt;
            rotList = bar;&lt;br /&gt;
            llMessageLinked(sender_num,-1,str,op_import);&lt;br /&gt;
            recordedSnapshots = num / (llGetNumberOfPrims() - 1);&lt;br /&gt;
            llMessageLinked(LINK_SET, recordedSnapshots, &amp;quot;XDrecordedSnapshots&amp;quot;, NULL_KEY);&lt;br /&gt;
            currentSnapshot = 1;&lt;br /&gt;
        }else if(&amp;quot;XDrecordedSnapshots&amp;quot; == str &amp;amp;&amp;amp; num == -1){&lt;br /&gt;
            llMessageLinked(sender_num,recordedSnapshots,str,NULL_KEY);&lt;br /&gt;
        }else if(id == op_import &amp;amp;&amp;amp; num &amp;gt;= 0){&lt;br /&gt;
            list params = llParseString2List(str, [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
            vector impPos = (vector)llList2String(params,0);&lt;br /&gt;
            rotation impRot = (rotation)llList2String(params,1);&lt;br /&gt;
            vector impSize  = (vector)llList2String(params,2);&lt;br /&gt;
            posList = llListReplaceList(posList,[impPos],num,num);&lt;br /&gt;
            rotList = llListReplaceList(rotList,[impRot],num,num);&lt;br /&gt;
            scaleList = llListReplaceList(scaleList,[impSize],num,num);&lt;br /&gt;
        }else if(id == op_alter_rootScale){&lt;br /&gt;
            rootScale = (vector)str;&lt;br /&gt;
            calc_scaleChange();&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    //This event handler takes care of all the editing commands.&lt;br /&gt;
    //Available commands are: record, play, publish, show next, show prev, show #&lt;br /&gt;
    listen(integer channel, string name, key id, string message)&lt;br /&gt;
    {&lt;br /&gt;
        list parsedMessage = llParseString2List(message, [&amp;quot; &amp;quot;], []);&lt;br /&gt;
        string firstWord = llToLower(llList2String(parsedMessage,0));&lt;br /&gt;
        string secondWord = llToLower(llList2String(parsedMessage,1));&lt;br /&gt;
 &lt;br /&gt;
        //display a snapshot&lt;br /&gt;
        if(&amp;quot;show&amp;quot; == firstWord &amp;amp;&amp;amp; recordedSnapshots &amp;gt; 0)&lt;br /&gt;
        {&lt;br /&gt;
            //stop any currently playing animation.&lt;br /&gt;
            llSetTimerEvent(0);&lt;br /&gt;
 &lt;br /&gt;
            if(secondWord == &amp;quot;next&amp;quot;)&lt;br /&gt;
            {&lt;br /&gt;
                currentSnapshot++;&lt;br /&gt;
                if(currentSnapshot &amp;gt; recordedSnapshots)&lt;br /&gt;
                    currentSnapshot = 1;&lt;br /&gt;
 &lt;br /&gt;
                showSnapshot(currentSnapshot);&lt;br /&gt;
            }&lt;br /&gt;
            else if(secondWord == &amp;quot;prev&amp;quot;)&lt;br /&gt;
            {&lt;br /&gt;
                currentSnapshot--;&lt;br /&gt;
                if(currentSnapshot &amp;lt; 1)&lt;br /&gt;
                    currentSnapshot = recordedSnapshots;&lt;br /&gt;
 &lt;br /&gt;
                showSnapshot(currentSnapshot);&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                // when the conversion fails, snapshotNumber = 0&lt;br /&gt;
                currentSnapshot = (integer)secondWord;&lt;br /&gt;
                if(currentSnapshot &amp;gt; 0 &amp;amp;&amp;amp; currentSnapshot &amp;lt;= recordedSnapshots )&lt;br /&gt;
                {&lt;br /&gt;
                    showSnapshot(currentSnapshot);&lt;br /&gt;
                    llOwnerSay(&amp;quot;Showing snapshot: &amp;quot;+(string)currentSnapshot);&lt;br /&gt;
                }&lt;br /&gt;
                else&lt;br /&gt;
                {&lt;br /&gt;
                    llOwnerSay(&amp;quot;Invalid snapshot number given: &amp;quot; + (string) currentSnapshot +&lt;br /&gt;
                                &amp;quot;\nA valid snapshot number is between 1 and &amp;quot; + (string) recordedSnapshots);&lt;br /&gt;
                    currentSnapshot = 1;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        //record a snapshot&lt;br /&gt;
        else if(firstWord == &amp;quot;record&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            integer i = 0;&lt;br /&gt;
            //2 is the first linked prim number.&lt;br /&gt;
            vector rootPos = llGetPos();&lt;br /&gt;
            for( i = 2; i &amp;lt;= primCount; i++)&lt;br /&gt;
            {&lt;br /&gt;
                vector pos = llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_POSITION]),0);&lt;br /&gt;
                //need to convert into local position&lt;br /&gt;
                pos.x -= rootPos.x;&lt;br /&gt;
                pos.z -= rootPos.z;&lt;br /&gt;
                pos.y -= rootPos.y;&lt;br /&gt;
                pos = pos / llGetRot();&lt;br /&gt;
                posList += pos;&lt;br /&gt;
 &lt;br /&gt;
                rotation rot = llList2Rot(llGetLinkPrimitiveParams(i, [PRIM_ROTATION]),0);&lt;br /&gt;
                //Converting into local rot&lt;br /&gt;
                rot = rot / llGetRot();&lt;br /&gt;
                rotList += rot;&lt;br /&gt;
 &lt;br /&gt;
                scaleList += llList2Vector(llGetLinkPrimitiveParams(i, [PRIM_SIZE]),0);&lt;br /&gt;
            }&lt;br /&gt;
            recordedSnapshots++;&lt;br /&gt;
 &lt;br /&gt;
            llOwnerSay(&amp;quot;Total number of snapshots recorded: &amp;quot; + (string)recordedSnapshots);&lt;br /&gt;
            freeMemory = llGetFreeMemory();&lt;br /&gt;
        }&lt;br /&gt;
        //play the animation from beginning to end once without looping.&lt;br /&gt;
        else if (firstWord == &amp;quot;play&amp;quot;)&lt;br /&gt;
        {&lt;br /&gt;
            float delay = (float)secondWord;&lt;br /&gt;
            currentSnapshot = 1;&lt;br /&gt;
            //play the animation once without loop&lt;br /&gt;
            playAnimation(delay, FALSE);&lt;br /&gt;
        }&lt;br /&gt;
        //publish disables the recording features and enables the on-touch trigger&lt;br /&gt;
        else if(&amp;quot;publish&amp;quot; == firstWord)&lt;br /&gt;
        {&lt;br /&gt;
            //stop any currently playing animation.&lt;br /&gt;
            llSetTimerEvent(0);&lt;br /&gt;
            playAnimationStyle = 0;&lt;br /&gt;
            currentSnapshot = 1;&lt;br /&gt;
 &lt;br /&gt;
            //remove listeners to disable recording&lt;br /&gt;
            llListenRemove(commandListenerHandle);&lt;br /&gt;
            commandListenerHandle = -1; //indicating that it&#039;s been published&lt;br /&gt;
 &lt;br /&gt;
            llOwnerSay(&amp;quot;Recording disabled. Publish complete.\nClick me to toggle animation on/off.&amp;quot;);&lt;br /&gt;
        }else if(&amp;quot;loop&amp;quot; == firstWord){&lt;br /&gt;
            llMessageLinked(LINK_THIS,0,&amp;quot;XDplayLoop&amp;quot;,NULL_KEY);&lt;br /&gt;
        }else if(&amp;quot;stop&amp;quot; == firstWord){&lt;br /&gt;
            llMessageLinked(LINK_THIS,0,&amp;quot;XDstop&amp;quot;,NULL_KEY);&lt;br /&gt;
        }else if(&amp;quot;export&amp;quot; == firstWord){&lt;br /&gt;
            llOwnerSay(&amp;quot;Should be exporting&amp;quot;);&lt;br /&gt;
            llMessageLinked(LINK_THIS,0,&amp;quot;XDexport&amp;quot;,NULL_KEY);&lt;br /&gt;
        }&lt;br /&gt;
 &lt;br /&gt;
        //if not published, show menu&lt;br /&gt;
        if(commandListenerHandle != -1)&lt;br /&gt;
            showMenuDialog();&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    //Timer event is used to handle the animation playback.&lt;br /&gt;
    timer()&lt;br /&gt;
    {&lt;br /&gt;
        showSnapshot(currentSnapshot);&lt;br /&gt;
 &lt;br /&gt;
        //if not at the end of the animation, increment the counter&lt;br /&gt;
        if(currentSnapshot &amp;lt; recordedSnapshots)&lt;br /&gt;
            currentSnapshot++;&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            // if animation is looping, set the counter back to 1&lt;br /&gt;
            if( playAnimationStyle == 2)&lt;br /&gt;
                currentSnapshot = 1;&lt;br /&gt;
            // if animation isn&#039;t looping, stop the animation&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                llSetTimerEvent(0);&lt;br /&gt;
                //if not published, show dialog menu&lt;br /&gt;
                if(commandListenerHandle != -1)&lt;br /&gt;
                    showMenuDialog();&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Linden_Lab_Official_talk:Linden_Dollar_Exchange_(LindeX)&amp;diff=1151618</id>
		<title>Linden Lab Official talk:Linden Dollar Exchange (LindeX)</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Linden_Lab_Official_talk:Linden_Dollar_Exchange_(LindeX)&amp;diff=1151618"/>
		<updated>2011-08-18T11:54:21Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: /* Misleading Eldex adverts */ new section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Virwox has an exchange for U.S. dollars also. &lt;br /&gt;
[[User:Prokofy Neva|Prokofy Neva]] 04:52, 2 November 2010 (UTC) Prokofy Neva&lt;br /&gt;
:Maybe they do not use the Exchange Risk API? -- &#039;&#039;&#039;[[User:Strife_Onizuka|Strife]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Strife_Onizuka|talk]]|[[Special:Contributions/Strife_Onizuka|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 16:05, 2 November 2010 (UTC)&lt;br /&gt;
&lt;br /&gt;
== Misleading Eldex adverts ==&lt;br /&gt;
&lt;br /&gt;
Was on Facebook earlier, and a potentially misleading advert cropped up; image: https://fbcdn-photos-a.akamaihd.net/photos-ak-snc1/v41818/flyers/31/0/1299699951315133482_1_d942dcdd.jpg&lt;br /&gt;
&lt;br /&gt;
text: &amp;quot;Official  exchange partner of Linden Lab. Buy and Sell L$ against real  currencies. Affiliate program for businesses. Customer support.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
they&#039;ve also got this image on their website: https://www.eldexchange.eu/templates/ildex-home/images/slpartner2.jpg&lt;br /&gt;
&lt;br /&gt;
Is the &amp;quot;official exchange partner&amp;quot; a phrase that third-party exchanges are permitted to use ?&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[User:SignpostMarv Martin|SignpostMarv Martin]] 04:54, 18 August 2011 (PDT)&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Content_Creation/Mesh_Import/Scripting_User_Group/Archive&amp;diff=1142925</id>
		<title>Content Creation/Mesh Import/Scripting User Group/Archive</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Content_Creation/Mesh_Import/Scripting_User_Group/Archive&amp;diff=1142925"/>
		<updated>2011-05-09T16:25:15Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: moved Content Creation/Mesh Import/Scripting User Group/Archive to Content Creation, Mesh Import, Scripting User Group/Archive:&amp;amp;#32;noted as commas in AW Groupies chat&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Content Creation, Mesh Import, Scripting User Group/Archive]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Content_Creation,_Mesh_Import_User_Group/Archive&amp;diff=1142924</id>
		<title>Content Creation, Mesh Import User Group/Archive</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Content_Creation,_Mesh_Import_User_Group/Archive&amp;diff=1142924"/>
		<updated>2011-05-09T16:25:15Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: moved Content Creation/Mesh Import/Scripting User Group/Archive to Content Creation, Mesh Import, Scripting User Group/Archive:&amp;amp;#32;noted as commas in AW Groupies chat&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;===Archived Agenda/Meeting Notes===&lt;br /&gt;
&lt;br /&gt;
[https://wiki.secondlife.com/wiki/Mesh/Archive/2011-05-02 2011-05-02]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.secondlife.com/wiki/Mesh/Archive/2011-04-25 2011-04-25]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.secondlife.com/wiki/Mesh/Archive/2011-04-18 2011-04-18]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.secondlife.com/wiki/Mesh/Archive/2011-04-11 2011-04-11]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.secondlife.com/wiki/Mesh/Archive/2011-04-04 2011-04-04]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.secondlife.com/wiki/Mesh/Archive/2011-03-28 2011-03-28]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.secondlife.com/wiki/Mesh/Archive/2011-03-21 2011-03-21]&lt;br /&gt;
&lt;br /&gt;
[https://wiki.secondlife.com/wiki/Mesh/Archive/2011-03-14 2011-03-14]&lt;br /&gt;
&lt;br /&gt;
[http://wiki.secondlife.com/wiki/Mesh/Archive/2011-03-07 2011-03-07]&lt;br /&gt;
&lt;br /&gt;
[http://wiki.secondlife.com/wiki/Mesh/Archive/2011-02-28 2011-02-28]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[https://wiki.secondlife.com/wiki/User:Nyx_Linden/Mesh_Office_Hours_Agenda_Archive Prior meeting notes]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Mesh]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Content_Creation/Mesh_Import/Scripting_User_Group&amp;diff=1142923</id>
		<title>Content Creation/Mesh Import/Scripting User Group</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Content_Creation/Mesh_Import/Scripting_User_Group&amp;diff=1142923"/>
		<updated>2011-05-09T16:25:14Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: moved Content Creation/Mesh Import/Scripting User Group to Content Creation, Mesh Import, Scripting User Group:&amp;amp;#32;noted as commas in AW Groupies chat&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Content Creation, Mesh Import, Scripting User Group]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Content_Creation,_Mesh_Import,_Scripting_User_Group&amp;diff=1142922</id>
		<title>Content Creation, Mesh Import, Scripting User Group</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Content_Creation,_Mesh_Import,_Scripting_User_Group&amp;diff=1142922"/>
		<updated>2011-05-09T16:25:14Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: moved Content Creation/Mesh Import/Scripting User Group to Content Creation, Mesh Import, Scripting User Group:&amp;amp;#32;noted as commas in AW Groupies chat&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{User Group Page&lt;br /&gt;
|purpose=&lt;br /&gt;
Although the header says &amp;quot;Content Creation/Mesh Import/Scripting&amp;quot;, currently topics are focused on anything related to the mesh import project. Feature requests, bug reports, design feedback, questions, comments, or example content are welcome.&lt;br /&gt;
&lt;br /&gt;
Priority will be given to topics that are posted in advance and are relevant to the goals of the office hour. Feel free to include relevant links to JIRA or wiki pages. &lt;br /&gt;
&lt;br /&gt;
|date-time= &lt;br /&gt;
Mondays at 11 AM in Pacific time (SL standard time)&lt;br /&gt;
&lt;br /&gt;
Next meeting scheduled for: &#039;&#039;&#039;May 9, 2011&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
|location= &lt;br /&gt;
[secondlife://Aditi/secondlife/MeshHQ%201/251/250/24 Mesh HQ on Aditi]&lt;br /&gt;
|team=&lt;br /&gt;
Charlar Linden, Nyx Linden, and Runitai Linden. Please contact one of us if you are unsure if your topic is relevant or appropriate.&lt;br /&gt;
|agenda=&lt;br /&gt;
&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
Please add topics below &#039;&#039;&#039;prior to 10:50 AM&#039;&#039;&#039;. Also, please put your SL name down so we can follow up if we have questions. Thanks!&lt;br /&gt;
# New Usergroup time, starting next week! [Nyx Linden]&lt;br /&gt;
# Can you explain how undecomposed prim-type physics shapes are made? In physics shape display I see one-sided surfaces, missing sides of solids, and small small features absent. Decomposed surfaces are 2-sided. [Drongle McMahon]&lt;br /&gt;
# Can you update us on recent progress and tell us what your current priorities are? [Vivienne Daguerre]&lt;br /&gt;
# Is there anything in particular you need us to test? [Vivienne Daguerre]&lt;br /&gt;
# Please give an update on re-adding bone length recognition to the importer.&lt;br /&gt;
# Why do some cts jiras get spirited off into Shining, leaving no trace in cts? [Drongle]&lt;br /&gt;
# Will LL support or quash the XML hack that allows sculpties to have texture faces? [Bloodsong Termagant]&lt;br /&gt;
# I am working on rideables.  If one mesh leg costs about 20 prims, and at least 6 alpha iterations are needed to animate each of the 4 legs, that would be 480 prims for the legs alone (and not account for the body, head, neck, and all those flexiprims needed for manes and tails).  While scripts are happy, because each mesh object is one link in a set, and avatars don&#039;t care because they don&#039;t (yet) have a prim limit on what they can wear; wouldn&#039;t such a mesh rideable cause a huge amount of prim lag?  Should I shelve this project, at least until/unless independantly rigged animated mesh items are supported?  If independantly rigged meshes are introduced at some later date, will they still work when worn by an avatar (and not try to glom onto the avatar&#039;s armature)? [Bloodsong Termagant]&lt;br /&gt;
# please add your agenda items here&lt;br /&gt;
&lt;br /&gt;
|archive=&lt;br /&gt;
* [[Mesh_User_Group/Archive|Agenda and notes archive]]&lt;br /&gt;
*   [[User:Nyx_Linden/Mesh_Office_Hours_Agenda_Archive|Older archives]]&lt;br /&gt;
}}&lt;br /&gt;
[[Category:Mesh]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Wiki_Acceptance_Tests&amp;diff=1133074</id>
		<title>Wiki Acceptance Tests</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Wiki_Acceptance_Tests&amp;diff=1133074"/>
		<updated>2011-02-02T07:37:18Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: /* Time */  adding more tests&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;When upgrading the wiki, or moving to a new operational location, use these tests to ensure that everything is functional.&lt;br /&gt;
&lt;br /&gt;
In all cases, the pages should look the same as they did previously.&lt;br /&gt;
The best way to ensure this would be to compare their appearance in the new installation with their appearance in the old (existing) installation.&lt;br /&gt;
&lt;br /&gt;
== Upgrade notes ==&lt;br /&gt;
&lt;br /&gt;
With this upgrade, we are also upgrading a number of extensions.  There may be some backward-incompatibilities that require content changes:&lt;br /&gt;
* The newer version of the ImageMap extension requires polygon shapes to have an even number of points.&lt;br /&gt;
&lt;br /&gt;
=== Browser compatibility ===&lt;br /&gt;
&lt;br /&gt;
Test with the following browsers:&lt;br /&gt;
* FireFox&lt;br /&gt;
* Chrome&lt;br /&gt;
* Safari&lt;br /&gt;
* Opera&lt;br /&gt;
* IE&lt;br /&gt;
&lt;br /&gt;
I&#039;m not too worried about versions... as long as we&#039;re hitting with a version within the last two major releases.. nothing too old (aka Chrome 5 or 6, FF 3.5 or 3.6, IE 7 or 8, etc)&lt;br /&gt;
&lt;br /&gt;
=== Time ===&lt;br /&gt;
&lt;br /&gt;
* #time:Y-m-dTH:i:s+00:00 - {{#time:Y-m-dTH:i:s+00:00}}&lt;br /&gt;
* #time: Y-m-d H:i:s - {{#time: Y-m-d H:i:s}}&lt;br /&gt;
* #time: r|now - {{#time: r|now}}&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;{{#time: Y-m-d }}&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; → &#039;&#039;&#039;{{#time: Y-m-d }}&#039;&#039;&#039;&lt;br /&gt;
*&amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;{{#timel: Y-m-d }}&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; → &#039;&#039;&#039;{{#timel: Y-m-d }}&#039;&#039;&#039;&lt;br /&gt;
*&amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;{{#time: Y F d h:i:s}}&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; → &#039;&#039;&#039;{{#time: Y F d H:i:s}}&#039;&#039;&#039;&lt;br /&gt;
*&amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;{{#timel: Y F d h:i:s}}&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; → &#039;&#039;&#039;{{#timel: Y F d H:i:s}}&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;{{#time:c|11am PST}}&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; &#039;&#039;&#039;{{#time:c|11am PST}}&#039;&#039;&#039;&lt;br /&gt;
*&amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;{{#time:c|11am GMT}}&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; &#039;&#039;&#039;{{#time:c|11am GMT}}&#039;&#039;&#039;&lt;br /&gt;
*&amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;{{#timel:c|11am PST}}&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; &#039;&#039;&#039;{{#timel:c|11am PST}}&#039;&#039;&#039;&lt;br /&gt;
*&amp;lt;tt&amp;gt;&amp;lt;nowiki&amp;gt;{{#timel:c|11am GMT}}&amp;lt;/nowiki&amp;gt;&amp;lt;/tt&amp;gt; &#039;&#039;&#039;{{#timel:c|11am GMT}}&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* UTC: {{#time:c}}&lt;br /&gt;
* Local: {{#timel:c}}&lt;br /&gt;
&lt;br /&gt;
== Basic content tests ==&lt;br /&gt;
* [[Main Page]] - Check that it looks the same.&lt;br /&gt;
&lt;br /&gt;
=== Images and image pages ===&lt;br /&gt;
&lt;br /&gt;
Make sure all images appear properly, including the SL logo at upper left, CC and MW logos at the bottom, and uploaded images. &lt;br /&gt;
Here are a few examples:&lt;br /&gt;
&lt;br /&gt;
* [[:File:Doc office hour 2009-01-14.jpg]]&lt;br /&gt;
* [[:File:Kb ARC Default .png]]&lt;br /&gt;
* [[:File:V1.23 Cluttered Screen.jpg]]&lt;br /&gt;
* [[:File:Torley%27s_awesome_People_Tool_pic.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Special pages ===&lt;br /&gt;
* [[Special:Recentchanges]]&lt;br /&gt;
* [[Special:Version]] - check list of extensions and make sure it matches.&lt;br /&gt;
&lt;br /&gt;
=== API ===&lt;br /&gt;
&lt;br /&gt;
To check that the API is active, click this link: &lt;br /&gt;
{{SERVER}}{{SCRIPTPATH}}/api.php&lt;br /&gt;
&lt;br /&gt;
=== HTTPS ===&lt;br /&gt;
&lt;br /&gt;
Nowhere on the site should there be HTTPS errors (i.e. broken lock in the browser), especially not on the Login page. Acid test is IE, which complains the most. Chrome has a weird bug where sometimes it&#039;ll complain about HTTPS problems while no other browser does.&lt;br /&gt;
&lt;br /&gt;
Pages to test:&lt;br /&gt;
* Front page&lt;br /&gt;
* Login page&lt;br /&gt;
* User page (Torley&#039;s?)&lt;br /&gt;
* File:Image page&lt;br /&gt;
&lt;br /&gt;
=== Namespaces ===&lt;br /&gt;
&lt;br /&gt;
The following query returns a list of the namespaces defined:&lt;br /&gt;
&lt;br /&gt;
* {{SERVER}}{{SCRIPTPATH}}/api.php?action=query&amp;amp;meta=siteinfo&amp;amp;siprop=general|namespaces|namespacealiases|statistics&lt;br /&gt;
This should return the following:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;api&amp;gt;&lt;br /&gt;
  &amp;lt;query&amp;gt;&lt;br /&gt;
    &amp;lt;general mainpage=&amp;quot;Main Page&amp;quot; base=&amp;quot;https://wiki.secondlife.com/wiki/Main_Page&amp;quot; sitename=&amp;quot;Second Life Wiki&amp;quot; generator=&amp;quot;MediaWiki 1.14.1&amp;quot; rev=&amp;quot;34&amp;quot; case=&amp;quot;first-letter&amp;quot; rights=&amp;quot;Creative Commons Attribution-Share Alike 3.0&amp;quot; lang=&amp;quot;en&amp;quot; fallback8bitEncoding=&amp;quot;windows-1252&amp;quot; writeapi=&amp;quot;&amp;quot; timezone=&amp;quot;UTC&amp;quot; timeoffset=&amp;quot;0&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;namespaces&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;-2&amp;quot; canonical=&amp;quot;Media&amp;quot;&amp;gt;Media&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;-1&amp;quot; canonical=&amp;quot;Special&amp;quot;&amp;gt;Special&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;0&amp;quot; subpages=&amp;quot;&amp;quot; /&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;1&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Talk&amp;quot;&amp;gt;Talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;2&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;User&amp;quot;&amp;gt;User&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;3&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;User talk&amp;quot;&amp;gt;User talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;4&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Project&amp;quot;&amp;gt;Project&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;5&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Project talk&amp;quot;&amp;gt;Project talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;6&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;File&amp;quot;&amp;gt;File&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;7&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;File talk&amp;quot;&amp;gt;File talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;8&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;MediaWiki&amp;quot;&amp;gt;MediaWiki&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;9&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;MediaWiki talk&amp;quot;&amp;gt;MediaWiki talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;10&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Template&amp;quot;&amp;gt;Template&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;11&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Template talk&amp;quot;&amp;gt;Template talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;12&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Help&amp;quot;&amp;gt;Help&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;13&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Help talk&amp;quot;&amp;gt;Help talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;14&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Category&amp;quot;&amp;gt;Category&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;15&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Category talk&amp;quot;&amp;gt;Category talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;100&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Linden Lab Official&amp;quot;&amp;gt;Linden Lab Official&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;101&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Linden Lab Official talk&amp;quot;&amp;gt;Linden Lab Official talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;102&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Viewerhelp&amp;quot;&amp;gt;Viewerhelp&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;103&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Viewerhelp talk&amp;quot;&amp;gt;Viewerhelp talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;104&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Article officiel de Linden Lab&amp;quot;&amp;gt;Article officiel de Linden Lab&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;105&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Article officiel de Linden Lab talk&amp;quot;&amp;gt;Article officiel de Linden Lab talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;106&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Linden Lab公認&amp;quot;&amp;gt;Linden Lab公認&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;107&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Linden Lab公認 talk&amp;quot;&amp;gt;Linden Lab公認 talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;108&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Articolo ufficiale Linden Lab&amp;quot;&amp;gt;Articolo ufficiale Linden Lab&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;109&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Articolo ufficiale Linden Lab talk&amp;quot;&amp;gt;Articolo ufficiale Linden Lab talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;110&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Artigo oficial da Linden Lab&amp;quot;&amp;gt;Artigo oficial da Linden Lab&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;111&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Artigo oficial da Linden Lab talk&amp;quot;&amp;gt;Artigo oficial da Linden Lab talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;112&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Artículo oficial de Linden Lab&amp;quot;&amp;gt;Artículo oficial de Linden Lab&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;113&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Artículo oficial de Linden Lab talk&amp;quot;&amp;gt;Artículo oficial de Linden Lab talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;114&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Linden Lab Offiziell&amp;quot;&amp;gt;Linden Lab Offiziell&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;115&amp;quot; subpages=&amp;quot;&amp;quot; canonical=&amp;quot;Linden Lab Offiziell talk&amp;quot;&amp;gt;Linden Lab Offiziell talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;274&amp;quot; canonical=&amp;quot;Widget&amp;quot;&amp;gt;Widget&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;275&amp;quot; canonical=&amp;quot;Widget talk&amp;quot;&amp;gt;Widget talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
    &amp;lt;/namespaces&amp;gt;&lt;br /&gt;
    &amp;lt;namespacealiases&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;100&amp;quot;&amp;gt;LLO&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;114&amp;quot;&amp;gt;LLOde&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;104&amp;quot;&amp;gt;LLOfr&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;106&amp;quot;&amp;gt;LLOja&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;108&amp;quot;&amp;gt;LLOit&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;110&amp;quot;&amp;gt;LLOpt&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;112&amp;quot;&amp;gt;LLOes&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;6&amp;quot;&amp;gt;Image&amp;lt;/ns&amp;gt;&lt;br /&gt;
      &amp;lt;ns id=&amp;quot;7&amp;quot;&amp;gt;Image talk&amp;lt;/ns&amp;gt;&lt;br /&gt;
    &amp;lt;/namespacealiases&amp;gt;&lt;br /&gt;
    &amp;lt;statistics pages=&amp;quot;33962&amp;quot; articles=&amp;quot;8215&amp;quot; views=&amp;quot;118745206&amp;quot; edits=&amp;quot;187815&amp;quot; images=&amp;quot;5426&amp;quot; users=&amp;quot;50807&amp;quot; activeusers=&amp;quot;240&amp;quot; admins=&amp;quot;33&amp;quot; jobs=&amp;quot;0&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;/query&amp;gt;&lt;br /&gt;
&amp;lt;/api&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Protected namespaces ===&lt;br /&gt;
&lt;br /&gt;
* Make sure only Lindens can edit pages in the LLO namespacee, e.g. [[Linden Lab Official:Abandoned Land FAQ]].&lt;br /&gt;
&lt;br /&gt;
=== Search ===&lt;br /&gt;
Test &amp;quot;Google Search&amp;quot; in the sidebar:&lt;br /&gt;
# Enter a search term.&lt;br /&gt;
# Click &#039;&#039;&#039;Google Search&#039;&#039;&#039;.&lt;br /&gt;
Make sure it returns reasonable results.&lt;br /&gt;
&lt;br /&gt;
=== Subpages in main namespace===&lt;br /&gt;
&lt;br /&gt;
Go to [[Wiki Acceptance Test/Subpages]] -- first line should just say &amp;quot;Wiki Acceptance Test&amp;quot;, second line should just say &amp;quot;Subpages&amp;quot;. If they both say &amp;quot;Wiki Acceptance Test/Subpages&amp;quot;, then this isn&#039;t working right.&lt;br /&gt;
&lt;br /&gt;
== Extensions ==&lt;br /&gt;
&lt;br /&gt;
Check that [[Special:Version]] lists the same set of installed extensions.&lt;br /&gt;
&lt;br /&gt;
=== Cite ===&lt;br /&gt;
&lt;br /&gt;
The special page [[Special:Cite]] should exist.&lt;br /&gt;
&lt;br /&gt;
=== Flagged Revisions ===&lt;br /&gt;
&lt;br /&gt;
# Edit a page in the [[Knowledge Base]].&lt;br /&gt;
# Check that the edit becomes a &amp;quot;draft&amp;quot; revision.&lt;br /&gt;
# As a reviewer user, approve the edit, and check that it becomes the &amp;quot;stable&amp;quot; revision.&lt;br /&gt;
&lt;br /&gt;
Check the [[Admin Dashboard]] to ensure that pages show up in the various FR special pages.&lt;br /&gt;
&lt;br /&gt;
=== ImageMap ===&lt;br /&gt;
&lt;br /&gt;
Copied from [[User:Ugleh Ulrik]]:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example of known error&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
{| cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot; border=&amp;quot;0&amp;quot;&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|&amp;lt;imagemap&amp;gt;&lt;br /&gt;
Image:Ugleh_chat_top.png&lt;br /&gt;
poly 0 [[User:Ugleh Ulrik]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;imagemap&amp;gt; &lt;br /&gt;
Image:Ugleh_chat_left.png&lt;br /&gt;
poly 0 0 [[User:Ugleh Ulrik]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|style=&amp;quot;background:#3E3E3E;&amp;quot; valign=&amp;quot;top&amp;quot; width=&amp;quot;394&amp;quot; align=&amp;quot;left&amp;quot;|{{:User:Ugleh_Ulrik/quote}}&lt;br /&gt;
|&amp;lt;imagemap&amp;gt;&lt;br /&gt;
Image:Ugleh_chat_right.png&lt;br /&gt;
poly 0 [[User:Ugleh Ulrik]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|&amp;lt;imagemap&amp;gt;&lt;br /&gt;
Image:Ugleh_chat_bottom.png|&lt;br /&gt;
poly 0 [[User:Ugleh Ulrik]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example of corrected image map&#039;&#039;&#039;:&lt;br /&gt;
{| cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot; border=&amp;quot;0&amp;quot;&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|&amp;lt;imagemap&amp;gt;&lt;br /&gt;
Image:Ugleh_chat_top.png&lt;br /&gt;
poly 0 0 [[User:Ugleh Ulrik]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;imagemap&amp;gt; &lt;br /&gt;
Image:Ugleh_chat_left.png&lt;br /&gt;
poly 0 0 [[User:Ugleh Ulrik]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|style=&amp;quot;background:#3E3E3E;&amp;quot; valign=&amp;quot;top&amp;quot; width=&amp;quot;394&amp;quot; align=&amp;quot;left&amp;quot;|{{:User:Ugleh_Ulrik/quote}}&lt;br /&gt;
|&amp;lt;imagemap&amp;gt;&lt;br /&gt;
Image:Ugleh_chat_right.png&lt;br /&gt;
poly 0 0 [[User:Ugleh Ulrik]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|colspan=&amp;quot;3&amp;quot;|&amp;lt;imagemap&amp;gt;&lt;br /&gt;
Image:Ugleh_chat_bottom.png|&lt;br /&gt;
poly 0 0 [[User:Ugleh Ulrik]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== MathStatFunctions ===&lt;br /&gt;
&lt;br /&gt;
If these show the correct values, then this extension is working:&lt;br /&gt;
&lt;br /&gt;
*pi = {{ #const: pi }}&lt;br /&gt;
*e = {{ #const: e }}&lt;br /&gt;
*sqrt(2) = {{#const:sqrt(2)}}&lt;br /&gt;
&lt;br /&gt;
===SimpleTable===&lt;br /&gt;
&lt;br /&gt;
See [[Performance Testers#Results]].&lt;br /&gt;
&lt;br /&gt;
===Variables===&lt;br /&gt;
&lt;br /&gt;
Set the variable &amp;quot;myvar&amp;quot; to be &amp;quot;1234: {{#vardefine:myvar|1234}}&lt;br /&gt;
&lt;br /&gt;
If the following shows &amp;quot;1234&amp;quot;, then this is working properly:&lt;br /&gt;
&lt;br /&gt;
The value is &amp;gt;&amp;gt;&amp;gt; {{#var:myvar}} &amp;lt;&amp;lt;&amp;lt;&lt;br /&gt;
&lt;br /&gt;
===VideoFlash 	===&lt;br /&gt;
&lt;br /&gt;
===Widgets ===&lt;br /&gt;
Check that the following list of widgets shows up: https://wiki.secondlife.com/w/index.php?title=Special%3AAllPages&amp;amp;from=&amp;amp;to=&amp;amp;namespace=274&lt;br /&gt;
&lt;br /&gt;
* [[Widget:Blip.tv]]&lt;br /&gt;
* [[Widget:Chat Transcript]]&lt;br /&gt;
* [[Widget:Feed]]&lt;br /&gt;
* [[Widget:Flickr]]&lt;br /&gt;
* [[Widget:Flickr/SlideShow]]&lt;br /&gt;
* [[Widget:Flickr/Slideshow]]&lt;br /&gt;
* [[Widget:FlickrShow]]&lt;br /&gt;
* [[Widget:Google Gadget]]&lt;br /&gt;
* [[Widget:Scribd]]&lt;br /&gt;
* [[Widget:SlideShare]]&lt;br /&gt;
* [[Widget:Twitter]]&lt;br /&gt;
* [[Widget:Vimeo]]&lt;br /&gt;
* [[Widget:Widgetbox]]&lt;br /&gt;
* [[Widget:YouTube]]&lt;br /&gt;
* [[Widget:YouTubeChannel]]&lt;br /&gt;
&lt;br /&gt;
Do we need to test each individual widget?  Probably not.  Maybe just test a couple.&lt;br /&gt;
&lt;br /&gt;
===Add metas ===&lt;br /&gt;
&lt;br /&gt;
Check that each page has &lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;meta name=&amp;quot;mat&amp;quot; content=&amp;quot;PG_NOT&amp;quot; /&amp;gt; &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in its &amp;lt;head&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Breadcrumbs2 ===&lt;br /&gt;
Check that [[MediaWiki:Breadcrumbs]] exists and that breadcrumbs are displayed properly.&lt;br /&gt;
&lt;br /&gt;
===GeSHiHighlight===&lt;br /&gt;
&lt;br /&gt;
If the following is displayed as formatted text the extension is working.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;default { state_entry() { llOwnerSay(&amp;quot;&amp;quot;); } }&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Also see [[Syntax Highlighting Examples]].&lt;br /&gt;
&lt;br /&gt;
===Google Analytics Integration ===&lt;br /&gt;
&lt;br /&gt;
Check that each wiki page has the following at the bottom:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
var gaJsHost = ((&amp;quot;https:&amp;quot; == document.location.protocol) ? &amp;quot;https://ssl.&amp;quot; : &amp;quot;http://www.&amp;quot;);&lt;br /&gt;
document.write(unescape(&amp;quot;%3Cscript src=&#039;&amp;quot; + gaJsHost + &amp;quot;google-analytics.com/ga.js&#039; type=&#039;text/javascript&#039;%3E%3C/script%3E&amp;quot;));&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
var pageTracker = _gat._getTracker(&amp;quot;UA-190376-9&amp;quot;);&lt;br /&gt;
pageTracker._initData();&lt;br /&gt;
pageTracker._trackPageview();&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===HeaderFooter===&lt;br /&gt;
&lt;br /&gt;
Check that [https://wiki.secondlife.com/w/index.php?title=Special%3AAllPages&amp;amp;from=&amp;amp;to=&amp;amp;namespace=100 a page in the LLO namespace] shows the following header and footer:&lt;br /&gt;
* [[MediaWiki:Hf-nsheader-Linden Lab Official]]&lt;br /&gt;
* [[MediaWiki:Hf-nsfooter-Linden Lab Official]]&lt;br /&gt;
&lt;br /&gt;
=== Rename User ===&lt;br /&gt;
&lt;br /&gt;
See if [[Special:RenameUser]] exists.&lt;br /&gt;
&lt;br /&gt;
===ReplaceText===&lt;br /&gt;
If this page exists, then the extension is installed. [[Special:ReplaceText]].  Try it out and confirm that it works properly.&lt;br /&gt;
&lt;br /&gt;
===ParserFunctions===&lt;br /&gt;
&lt;br /&gt;
If what follows is the current date and time formatted as Y m d H:i:s then this extension is working.&lt;br /&gt;
&lt;br /&gt;
{{#time: Y m d H:i:s}}&lt;br /&gt;
&lt;br /&gt;
===StringFunctions===&lt;br /&gt;
&lt;br /&gt;
If the number on the line below is 4, then this extension is working.&lt;br /&gt;
&lt;br /&gt;
{{#len:test}}&lt;br /&gt;
&lt;br /&gt;
[[Category:Wiki]]&lt;br /&gt;
&lt;br /&gt;
===ImageMap and Variables over HTTP===&lt;br /&gt;
&lt;br /&gt;
~var={{#vardefine:var|value}}{{#var:var|has no value}}~&lt;br /&gt;
&amp;lt;imagemap&amp;gt;&lt;br /&gt;
Image:Ugleh_chat_bottom.png|&lt;br /&gt;
poly 0 0 [[User:Ugleh Ulrik]]&lt;br /&gt;
desc none&lt;br /&gt;
&amp;lt;/imagemap&amp;gt;&lt;br /&gt;
~var={{#var:var|has no value}}~&lt;br /&gt;
&lt;br /&gt;
HTTP: [http://{{SERVERNAME}}{{SCRIPTPATH}}/index.php?title={{FULLPAGENAMEE}} {{FULLPAGENAME}}]&lt;br /&gt;
HTTPS: [https://{{SERVERNAME}}{{SCRIPTPATH}}/index.php?title={{FULLPAGENAMEE}} {{FULLPAGENAME}}]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/sandbox&amp;diff=1133073</id>
		<title>User:SignpostMarv Martin/sandbox</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/sandbox&amp;diff=1133073"/>
		<updated>2011-02-02T07:34:01Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: adding moar tests&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* &amp;quot;{{#time:c|11am PST}}&amp;quot; &amp;lt;nowiki&amp;gt;{{#time:c|11am PST}}&amp;lt;/nowiki&amp;gt; should be -08:00, not +00:00&amp;quot; (see https://jira.secondlife.com/browse/WEB-3413)&lt;br /&gt;
* {{#timel:c|11am PST}} &amp;lt;nowiki&amp;gt;{{#timel:c|11am PST}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* {{#time:c|11am GMT}} &amp;lt;nowiki&amp;gt;{{#time:c|11am GMT}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* {{#timel:c|10am PST}} &amp;lt;nowiki&amp;gt;{{#timel:c|10am PST}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* {{#time:c|10am GMT}} &amp;lt;nowiki&amp;gt;{{#time:c|10am GMT}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;{{#vardefine:transcript_root|User:Torley Linden/Office Hours}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
Produces:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
{{#vardefine:transcript_root|User:Torley Linden/Office Hours}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Template:User_Groups/include-by-day&amp;diff=1133030</id>
		<title>Template:User Groups/include-by-day</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Template:User_Groups/include-by-day&amp;diff=1133030"/>
		<updated>2011-02-01T22:17:43Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: Redirected page to Template:Office Hours/include-by-day&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Template:Office Hours/include-by-day]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Template:Office_Hours/include-by-day&amp;diff=1133028</id>
		<title>Template:Office Hours/include-by-day</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Template:Office_Hours/include-by-day&amp;diff=1133028"/>
		<updated>2011-02-01T22:17:12Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: updating example&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;includeonly&amp;gt;{{{{{namespace|User}}}:{{{1}}}/{{#ifeq:{{{Teen|}}}|*|Teen_|}}Office Hours/{{{2}}}|mode={{{mode|}}}}}&amp;lt;/includeonly&amp;gt;&amp;lt;noinclude&amp;gt;Usage:&lt;br /&gt;
&amp;lt;nowiki&amp;gt;{{Office Hours/include-by-day|Oz Linden|Monday}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
{{Office Hours/include-by-day|Oz Linden|Monday}}&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Template:User_Groups/include&amp;diff=1133027</id>
		<title>Template:User Groups/include</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Template:User_Groups/include&amp;diff=1133027"/>
		<updated>2011-02-01T22:13:55Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: tweaky tweaky&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Template:Office Hours/include]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Template:User_Groups&amp;diff=1133025</id>
		<title>Template:User Groups</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Template:User_Groups&amp;diff=1133025"/>
		<updated>2011-02-01T22:10:46Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: Redirected page to Template:Office Hours&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Template:Office Hours]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/sandbox&amp;diff=1131493</id>
		<title>User:SignpostMarv Martin/sandbox</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/sandbox&amp;diff=1131493"/>
		<updated>2011-01-11T22:45:51Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: tweaking WEB-3413 test&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* &amp;quot;{{#time:c|11am PST}}&amp;quot; &amp;lt;nowiki&amp;gt;{{#time:c|11am PST}}&amp;lt;/nowiki&amp;gt; should be -08:00, not +00:00&amp;quot; (see https://jira.secondlife.com/browse/WEB-3413)&lt;br /&gt;
* {{#timel:c|11am PST}} &amp;lt;nowiki&amp;gt;{{#timel:c|11am PST}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* {{#time:c|11am GMT}} &amp;lt;nowiki&amp;gt;{{#time:c|11am GMT}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* {{#timel:c|11am GMT}} &amp;lt;nowiki&amp;gt;{{#timel:c|11am GMT}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;{{#vardefine:transcript_root|User:Torley Linden/Office Hours}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
Produces:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
{{#vardefine:transcript_root|User:Torley Linden/Office Hours}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/sandbox&amp;diff=1131492</id>
		<title>User:SignpostMarv Martin/sandbox</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/sandbox&amp;diff=1131492"/>
		<updated>2011-01-11T22:41:27Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: adding GMT&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* &amp;quot;{{#time:c|11am PST}}&amp;quot; &amp;lt;nowiki&amp;gt;{{#time:c|11am PST}}&amp;lt;/nowiki&amp;gt; should be -08:00, not +00:00&amp;quot; (see https://jira.secondlife.com/browse/WEB-3413)&lt;br /&gt;
* {{#timel:c|10am PST}} &amp;lt;nowiki&amp;gt;{{#timel:c|10am PST}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
* {{#timel:c|10am GMT}} &amp;lt;nowiki&amp;gt;{{#timel:c|10am GMT}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;{{#vardefine:transcript_root|User:Torley Linden/Office Hours}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
Produces:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
{{#vardefine:transcript_root|User:Torley Linden/Office Hours}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Map_API_VAG&amp;diff=1130870</id>
		<title>Map API VAG</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Map_API_VAG&amp;diff=1130870"/>
		<updated>2011-01-07T15:48:59Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: /* Related JIRA Issues */  adding WEB-1560&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;:this is an initial draft so scope and focus are still fairly open.  Please add comments to the [[{{TALKPAGENAME}}]] if you have slightly different viewpoints so we can try to converge on a common view. This discussion could also expose other similar VAG that are needed in this area&lt;br /&gt;
&lt;br /&gt;
The Map API Viewpoint Advocacy Group exists to ...  &lt;br /&gt;
&lt;br /&gt;
See the [[Architecture Working Group]] and the [[Viewpoint Advocacy Groups]] for more information.&lt;br /&gt;
&lt;br /&gt;
== Areas of concern addressed by the viewpoint ==&lt;br /&gt;
* Improving the usefulness of the Webmap API to both client, server and SL Viewer applications&lt;br /&gt;
* Permitting third-party developers to develop their own APIs by providing them with a data source suitable for updating their database&lt;br /&gt;
** Analysing use cases where the first party API is insufficient in order to improve the first party API&lt;br /&gt;
&lt;br /&gt;
== Source of Viewpoint ==&lt;br /&gt;
&lt;br /&gt;
== Use Cases ==&lt;br /&gt;
&lt;br /&gt;
See the [[Architecture Working Group Glossary]] and [[usecase templates]] for more information on creating usecases. One liners are fine (and better than nothing) but more detail will result in a better understanding and a better architecture.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Related JIRA Issues ==&lt;br /&gt;
The following JIRA issues are known problems that this VAG would like to see resolved in any future architecture.  The purpose of this list it to avoid problems that exist in the curent architecture. The more typical JIRAs that are more short term in nature or can be resolved by simple code or design change should not be listed here.&lt;br /&gt;
&lt;br /&gt;
* {{Jira|WEB-49}}, &#039;&#039;TSL lacks a Map API&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-87}} &#039;&#039;Webmap Images not updating&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-376}}, &#039;&#039;Map API does not properly handle SLPoint with region names&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-405}}, &#039;&#039;SLMAP API - disableVoiceInfo not working&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-473}}, &#039;&#039;webmap API indicates regions occupying multiple points in space simultaneously&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-474}}, &#039;&#039;Postcards need to send Global Coordinates since removal of SLPoint() from the SL Map API&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-503}}, &#039;&#039;sense; voice map API; it makes none, aka &amp;quot;query returns empty data set instead of error&#039;&#039;&lt;br /&gt;
* {{JIRA|WEB-504}}, &#039;&#039;PHP output mixed with javascript output&#039;&#039;&lt;br /&gt;
* {{JIRA|WEB-1560}}, &#039;&#039;Apply a OSS license to the SLURL.com JavaScript&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* [http://secondlife.com/developers/mapapi/ Legacy Linden Lab API]&lt;br /&gt;
* [[Webmap API|current Linden Lab API]]&lt;br /&gt;
* [[User:SignpostMarv_Martin/Webmap_API]]&lt;br /&gt;
* [[User:Thraxis Epsilon/map_api|TMS Webmap API Proposal]]&lt;br /&gt;
* [http://blog.signpostmarv.name/2008/07/29/non-unique-region-names-within-the-confines-of-a-single-grid-yay-or-nay/ non-unique region names within the confines of a single grid, yay or nay ?]&lt;br /&gt;
&lt;br /&gt;
== Organization ==&lt;br /&gt;
Anyone with an interest in this Viewpoint is welcome to join. You should join the [[AW Groupies]] group in Second Life.&lt;br /&gt;
&lt;br /&gt;
=== Members (Stakeholders) ===&lt;br /&gt;
* [[User:SignpostMarv Martin|SignpostMarv Martin]]&lt;br /&gt;
* [[User:Hackshaven Harford|Hackshaven Harford]]&lt;br /&gt;
* [[User:Ice Brodie|Ice Brodie]] - Unable to make meeting on the 22nd&lt;br /&gt;
* [[User:Yoz Linden|Yoz Linden]]&lt;br /&gt;
* [[User:Thraxis Epsilon|Thraxis Epsilon]]&lt;br /&gt;
&lt;br /&gt;
=== In world meetings ===&lt;br /&gt;
&lt;br /&gt;
# [[Map API VAG/2008-01-22| Tuesday 22nd January 2008, 9:30am]] [http://slurl.com/secondlife/Beaumont/42/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
# Thursday 11th November 2010, 2pm [http://mapapi.net/secondlife/Beaumont/41/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
#* Notes from agenda points discussed&lt;br /&gt;
#*# Discuss whether voicemap API should be retained&lt;br /&gt;
#*#* [http://img.skitch.com/20070724-xwds1wnqbmhqrc93nuajrew7yc.jpg Only visual record of the voicemap]&lt;br /&gt;
#*#* An educated guess would be that the voicemap API was left online by accident when the voicemap page was taken down.&lt;br /&gt;
#*#* Response from [[User:Yoz Linden|Yoz]]:&amp;lt;blockquote style=&amp;quot;border:3px solid #666;background:#eee;&amp;quot;&amp;gt;&amp;lt;p&amp;gt;[02:49 PM]  Yoz Linden: OK, then we return to my original statement&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[02:49 PM]  Yoz Linden: namely, that you can use it as long as you want, but I wouldn&#039;t rely on it existing permanently&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
#*# Discuss desirable API calls&lt;br /&gt;
#*#* Monolithic dump of region data, similar to the one that used to be contained in slmapapi.js consisting of at least the region names &amp;amp; co-ordinates, with region uuid, [[Beta|server version/channel]], region owner UUID, and a list of viewer features requiring server-side support (as voice/display names/mesh etc. can be rolled out selectively)&lt;br /&gt;
#*#* Having region servers push a data dump off their parcel&#039;s metadata to an S3 server&lt;br /&gt;
#*#* API/feed of region movement/renaming&lt;br /&gt;
# Thursday 18th November 2010, 2pm-3pm SLT [http://mapapi.net/secondlife/Beaumont/41/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
#* Notes from agenda points discussed&lt;br /&gt;
#*# Request the LDPW to make available and maintain APIs for notable locations/landmarks (see http://mapapi.net/secondlife/ for example implementations of such APIs)&lt;br /&gt;
#*#* Request subsets of the monolithic dump be provided to indicate which mainland regions belong to each continent&lt;br /&gt;
#*#* Request for a LDPW category be added to the destination guide&lt;br /&gt;
#*#* Request the provision of pre-baked overlays showing road/rail routes, or more preferably, a list of co-ordinates indicating way points for such routes (see http://mapapi.net/_data/grid-configs/com/secondlife/agni/roads.js for the kind of data required to generate route overlays dynamically)&lt;br /&gt;
#*#* Request the provision of APIs/data dumps of &amp;quot;Large region names&amp;quot; for places such as &amp;quot;Snowlands&amp;quot; &amp;quot;Bay City&amp;quot; &amp;quot;Linden Village&amp;quot; &amp;quot;Vehicle Sandbox&amp;quot; etc&lt;br /&gt;
#*#* Request estate owners be given the option to &amp;quot;publish estate name&amp;quot;, so that the estate name for a region may be listed amongst the meta tags on world.secondlife.com/region/ documents.&lt;br /&gt;
# &amp;lt;del&amp;gt;Thursday 25th November 2010, 2pm-3pm SLT&amp;lt;/del&amp;gt; &amp;lt;ins&amp;gt;postponed until WEB-1560 gets processed&amp;lt;/ins&amp;gt; [http://mapapi.net/secondlife/Beaumont/41/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
#* Agenda&lt;br /&gt;
#*# Discuss desirable API calls&lt;br /&gt;
#*#* Desirable data in a per-region parcel data dump&lt;br /&gt;
#*# Discuss potential benefits of {{Jira|WEB-1560|WEB-1560: Apply a OSS license (BSD or GPL) to the SLURL.com JavaScript}}&lt;br /&gt;
#*#* See http://mapapi.net/secondlife/ for an example&lt;br /&gt;
[[Category: AW Groupies]]&lt;br /&gt;
[[Category:Map API VAG]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Template:HCalendar_event/Office_Hours&amp;diff=1129179</id>
		<title>Template:HCalendar event/Office Hours</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Template:HCalendar_event/Office_Hours&amp;diff=1129179"/>
		<updated>2010-12-20T20:32:49Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: appears to be missing opening noinclude&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;onlyinclude&amp;gt;&amp;lt;includeonly&amp;gt;{{hCalendar event/Office Hours/{{{mode|default}}}&lt;br /&gt;
|dtstart={{{dtstart|}}}&lt;br /&gt;
|dtend={{{dtend|}}}&lt;br /&gt;
|Resident={{{Resident}}}&lt;br /&gt;
|namespace={{{namespace|User}}}&lt;br /&gt;
|description={{{description}}}&lt;br /&gt;
|location={{{location|}}}&lt;br /&gt;
|start={{{start|}}}&lt;br /&gt;
|end={{{end|}}}&lt;br /&gt;
|weekday={{{weekday|}}}&lt;br /&gt;
}}&lt;br /&gt;
{{#ifeq:{{NAMESPACE}}|User|{{#switch:{{SUBPAGENAME}}&lt;br /&gt;
|Office Hours=[[Category:Office Hours|{{{Resident}}}]]&lt;br /&gt;
|Teen Office Hours=[[Category:Office Hours|{{{Resident}}}]]}}{{#switch:{{{voice|}}}&lt;br /&gt;
|*=[[Category:Voice-Enabled Office Hours|{{{Resident}}}]]&lt;br /&gt;
|teen=[[Category:Voice-Enabled Office Hours|{{{Resident}}}]]}}|}}&amp;lt;/includeonly&amp;gt;&amp;lt;/onlyinclude&amp;gt;&amp;lt;noinclude&amp;gt;&lt;br /&gt;
{{hCalendar subscribe}}&lt;br /&gt;
== Convenience ==&lt;br /&gt;
The previous generation of Office Hours templates where created to improve productivity. Office Hours were being listed in multiple places- and as duplication of data increases, so does the effort to keep it all up to date.&lt;br /&gt;
&lt;br /&gt;
The problem then developed that Residents and Lindens alike wanted to be able to keep track of the events on Google Calendars, iCal and other calendar services/programs. There used to be an official calendar maintained by a Linden, which fell behind in updates, and there is now a calendar maintained by a Resident. The problem with maintaining a separate resource is that it needs to be kept up-to-date with any changes made.&lt;br /&gt;
&lt;br /&gt;
Which is where the hCalendar event templates come in- the ability to automate the generation of a calendar without relying on a Linden Lab employee or Resident to set aside some time/resources to maintain a calendar.&lt;br /&gt;
&lt;br /&gt;
== hCalendar ==&lt;br /&gt;
hCalendar is a [http://microformats.org/wiki/hcalendar microformat]- a series of class attributes and other standard HTML tricks that replicate the functionality of the pre-existing iCalendar standard (aka [http://www.ietf.org/rfc/rfc2445.txt RFC 2445]).&lt;br /&gt;
&lt;br /&gt;
hCalendar allows calendar data to be embedded in a web page without breaking the HTML standard, and also allows for the web page to be transposed easily into an iCalendar feed, via such 3rd party services as [http://technorati.com/events/ Technorati], or the W3C&#039;s own [http://www.w3.org/People/Bos/Hcalproxy/ hCal Proxy].&lt;br /&gt;
&lt;br /&gt;
== Usage ==&lt;br /&gt;
[[Image:Office Hours in Thunderbird.png|thumb|right|Embedded calendar data in Office Hours article being displayed in Thunderbird]]&lt;br /&gt;
The general behaviour that emerged from the Office Hours is that most office hours are done every week on the same day at the same time of day. This template acts as a wrapper which takes that behaviour into mind, simplifying the process of declaring the Office Hours as a recurring event.&lt;br /&gt;
&lt;br /&gt;
If an article lists events that use the hCalendar event series of templates, it is a good idea to include the [[Template:hCalendar subscribe|&amp;lt;nowiki&amp;gt;{{hCalendar subscribe}}&amp;lt;/nowiki&amp;gt; template ]] at the top of the page so that Residents can easily add the embedded calendar to their Calendar service/program.&lt;br /&gt;
&lt;br /&gt;
=== Variables ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Resident&#039;&#039;&#039;- The name of the Resident that is hosting the Office Hours&lt;br /&gt;
* &#039;&#039;&#039;description&#039;&#039;&#039;- A good place to let the other Residents know what&#039;ll be covered at your Office Hours&lt;br /&gt;
* &#039;&#039;&#039;weekday&#039;&#039;&#039;- What day of the week the Office Hours take place &#039;&#039;multiple templates will be required for each day Office Hours are held&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;start&#039;&#039;&#039;- What time of day the Office Hours start &#039;&#039;&#039;&#039;&#039;make sure to include the timezone!&#039;&#039;&#039;&#039;&#039; (PST and PDT will be auto-replaced to SLT for the convenience of Residents)&lt;br /&gt;
* &#039;&#039;&#039;end&#039;&#039;&#039;- What time of day the Office Hours finish &#039;&#039;&#039;&#039;&#039;make sure to include the timezone!&#039;&#039;&#039;&#039;&#039; (PST and PDT will be auto-replaced to SLT for the convenience of Residents)&lt;br /&gt;
* &#039;&#039;&#039;location&#039;&#039;&#039;- a SLurl to the location the Office Hours are held.&lt;br /&gt;
* &#039;&#039;&#039;voice&#039;&#039;&#039;- Whether or not the Office Hours will be voice-enabled.&lt;br /&gt;
** Use a single asterisk- &amp;quot;*&amp;quot; for the Main Grid,&lt;br /&gt;
** Use &amp;quot;teen&amp;quot; for the Teen Grid.&lt;br /&gt;
&lt;br /&gt;
=== Example ===&lt;br /&gt;
==== Default ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;{{hCalendar event/Office Hours&lt;br /&gt;
|Resident=Amber Linden&lt;br /&gt;
|description=Topics: General&lt;br /&gt;
|weekday=Monday&lt;br /&gt;
|start=9am PST&lt;br /&gt;
|end=10am PST&lt;br /&gt;
|location=[http://slurl.com/secondlife/Portage/14/154/98/?title=Second%20Life%20Helper%27s%20Lyceum Second Life Helper&#039;s Lyceum]&lt;br /&gt;
}}{{hCalendar event/Office Hours&lt;br /&gt;
|Resident=Amber Linden&lt;br /&gt;
|description=Topics: General&lt;br /&gt;
|weekday=Tuesday&lt;br /&gt;
|start=2pm PST&lt;br /&gt;
|end=3pm PST&lt;br /&gt;
|location=[http://slurl.com/secondlife/Portage/14/154/98/?title=Second%20Life%20Helper%27s%20Lyceum Second Life Helper&#039;s Lyceum]&lt;br /&gt;
}}&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
{{hCalendar event/Office Hours&lt;br /&gt;
|Resident=Amber Linden&lt;br /&gt;
|description=Topics: General&lt;br /&gt;
|weekday=Monday&lt;br /&gt;
|start=9am PST&lt;br /&gt;
|end=10am PST&lt;br /&gt;
|location=[http://slurl.com/secondlife/Portage/14/154/98/?title=Second%20Life%20Helper%27s%20Lyceum Second Life Helper&#039;s Lyceum]&lt;br /&gt;
}}{{hCalendar event/Office Hours&lt;br /&gt;
|Resident=Amber Linden&lt;br /&gt;
|description=Topics: General&lt;br /&gt;
|weekday=Tuesday&lt;br /&gt;
|start=2pm PST&lt;br /&gt;
|end=3pm PST&lt;br /&gt;
|location=[http://slurl.com/secondlife/Portage/14/154/98/?title=Second%20Life%20Helper%27s%20Lyceum Second Life Helper&#039;s Lyceum]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
=== tr ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&amp;lt;table class=&amp;quot;sortable&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Host&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Start Time&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;End Time&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Location&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
{{hCalendar event/Office Hours&lt;br /&gt;
|mode=tr&lt;br /&gt;
|Resident=Amber Linden&lt;br /&gt;
|description=Topics: General&lt;br /&gt;
|weekday=Monday&lt;br /&gt;
|start=9am PST&lt;br /&gt;
|end=10am PST&lt;br /&gt;
|location=[http://slurl.com/secondlife/Portage/14/154/98/?title=Second%20Life%20Helper%27s%20Lyceum Second Life Helper&#039;s Lyceum]&lt;br /&gt;
}}{{hCalendar event/Office Hours&lt;br /&gt;
|mode=tr&lt;br /&gt;
|Resident=Amber Linden&lt;br /&gt;
|description=Topics: General&lt;br /&gt;
|weekday=Tuesday&lt;br /&gt;
|start=2pm PST&lt;br /&gt;
|end=3pm PST&lt;br /&gt;
|location=[http://slurl.com/secondlife/Portage/14/154/98/?title=Second%20Life%20Helper%27s%20Lyceum Second Life Helper&#039;s Lyceum]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/table&amp;gt;&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;sortable&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Host&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Description&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Start Time&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;End Time&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Location&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;br /&gt;
{{hCalendar event/Office Hours&lt;br /&gt;
|mode=tr&lt;br /&gt;
|Resident=Amber Linden&lt;br /&gt;
|description=Topics: General&lt;br /&gt;
|weekday=Monday&lt;br /&gt;
|start=9am PST&lt;br /&gt;
|end=10am PST&lt;br /&gt;
|location=[http://slurl.com/secondlife/Portage/14/154/98/?title=Second%20Life%20Helper%27s%20Lyceum Second Life Helper&#039;s Lyceum]&lt;br /&gt;
}}{{hCalendar event/Office Hours&lt;br /&gt;
|mode=tr&lt;br /&gt;
|Resident=Amber Linden&lt;br /&gt;
|description=Topics: General&lt;br /&gt;
|weekday=Tuesday&lt;br /&gt;
|start=2pm PST&lt;br /&gt;
|end=3pm PST&lt;br /&gt;
|location=[http://slurl.com/secondlife/Portage/14/154/98/?title=Second%20Life%20Helper%27s%20Lyceum Second Life Helper&#039;s Lyceum]&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:hCalendar Templates|Office Hours]]&lt;br /&gt;
&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/sandbox&amp;diff=1129167</id>
		<title>User:SignpostMarv Martin/sandbox</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/sandbox&amp;diff=1129167"/>
		<updated>2010-12-20T19:12:28Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: testing timel&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* &amp;quot;{{#time:c|11am PST}}&amp;quot; &amp;lt;nowiki&amp;gt;{{#time:c|11am PST}}&amp;lt;/nowiki&amp;gt; should be -08:00, not +00:00&amp;quot; (see https://jira.secondlife.com/browse/WEB-3413)&lt;br /&gt;
* {{#timel:c|11am PST}} &amp;lt;nowiki&amp;gt;{{#timel:c|11am PST}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;{{#vardefine:transcript_root|User:Torley Linden/Office Hours}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
Produces:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
{{#vardefine:transcript_root|User:Torley Linden/Office Hours}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/sandbox&amp;diff=1129116</id>
		<title>User:SignpostMarv Martin/sandbox</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:SignpostMarv_Martin/sandbox&amp;diff=1129116"/>
		<updated>2010-12-20T14:51:00Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: WEB-3413&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;quot;{{#time:c|11am PST}}&amp;quot; should be -08:00, not +00:00&amp;quot; (see https://jira.secondlife.com/browse/WEB-3413)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;nowiki&amp;gt;{{#vardefine:transcript_root|User:Torley Linden/Office Hours}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
Produces:&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
{{#vardefine:transcript_root|User:Torley Linden/Office Hours}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;br /&gt;
{{:User:SignpostMarv Martin/sandbox/Template:Office Hours/transcript/year|2008}}&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Map_API_VAG&amp;diff=1114312</id>
		<title>Map API VAG</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Map_API_VAG&amp;diff=1114312"/>
		<updated>2010-11-25T21:07:14Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: /* In world meetings */ postponing meeting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;:this is an initial draft so scope and focus are still fairly open.  Please add comments to the [[{{TALKPAGENAME}}]] if you have slightly different viewpoints so we can try to converge on a common view. This discussion could also expose other similar VAG that are needed in this area&lt;br /&gt;
&lt;br /&gt;
The Map API Viewpoint Advocacy Group exists to ...  &lt;br /&gt;
&lt;br /&gt;
See the [[Architecture Working Group]] and the [[Viewpoint Advocacy Groups]] for more information.&lt;br /&gt;
&lt;br /&gt;
== Areas of concern addressed by the viewpoint ==&lt;br /&gt;
* Improving the usefulness of the Webmap API to both client, server and SL Viewer applications&lt;br /&gt;
* Permitting third-party developers to develop their own APIs by providing them with a data source suitable for updating their database&lt;br /&gt;
** Analysing use cases where the first party API is insufficient in order to improve the first party API&lt;br /&gt;
&lt;br /&gt;
== Source of Viewpoint ==&lt;br /&gt;
&lt;br /&gt;
== Use Cases ==&lt;br /&gt;
&lt;br /&gt;
See the [[Architecture Working Group Glossary]] and [[usecase templates]] for more information on creating usecases. One liners are fine (and better than nothing) but more detail will result in a better understanding and a better architecture.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Related JIRA Issues ==&lt;br /&gt;
The following JIRA issues are known problems that this VAG would like to see resolved in any future architecture.  The purpose of this list it to avoid problems that exist in the curent architecture. The more typical JIRAs that are more short term in nature or can be resolved by simple code or design change should not be listed here.&lt;br /&gt;
&lt;br /&gt;
* {{Jira|WEB-49}}, &#039;&#039;TSL lacks a Map API&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-87}} &#039;&#039;Webmap Images not updating&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-376}}, &#039;&#039;Map API does not properly handle SLPoint with region names&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-405}}, &#039;&#039;SLMAP API - disableVoiceInfo not working&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-473}}, &#039;&#039;webmap API indicates regions occupying multiple points in space simultaneously&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-474}}, &#039;&#039;Postcards need to send Global Coordinates since removal of SLPoint() from the SL Map API&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-503}}, &#039;&#039;sense; voice map API; it makes none, aka &amp;quot;query returns empty data set instead of error&#039;&#039;&lt;br /&gt;
* {{JIRA|WEB-504}}, &#039;&#039;PHP output mixed with javascript output&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* [http://secondlife.com/developers/mapapi/ Legacy Linden Lab API]&lt;br /&gt;
* [[Webmap API|current Linden Lab API]]&lt;br /&gt;
* [[User:SignpostMarv_Martin/Webmap_API]]&lt;br /&gt;
* [[User:Thraxis Epsilon/map_api|TMS Webmap API Proposal]]&lt;br /&gt;
* [http://blog.signpostmarv.name/2008/07/29/non-unique-region-names-within-the-confines-of-a-single-grid-yay-or-nay/ non-unique region names within the confines of a single grid, yay or nay ?]&lt;br /&gt;
&lt;br /&gt;
== Organization ==&lt;br /&gt;
Anyone with an interest in this Viewpoint is welcome to join. You should join the [[AW Groupies]] group in Second Life.&lt;br /&gt;
&lt;br /&gt;
=== Members (Stakeholders) ===&lt;br /&gt;
* [[User:SignpostMarv Martin|SignpostMarv Martin]]&lt;br /&gt;
* [[User:Hackshaven Harford|Hackshaven Harford]]&lt;br /&gt;
* [[User:Ice Brodie|Ice Brodie]] - Unable to make meeting on the 22nd&lt;br /&gt;
* [[User:Yoz Linden|Yoz Linden]]&lt;br /&gt;
* [[User:Thraxis Epsilon|Thraxis Epsilon]]&lt;br /&gt;
&lt;br /&gt;
=== In world meetings ===&lt;br /&gt;
&lt;br /&gt;
# [[Map API VAG/2008-01-22| Tuesday 22nd January 2008, 9:30am]] [http://slurl.com/secondlife/Beaumont/42/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
# Thursday 11th November 2010, 2pm [http://mapapi.net/secondlife/Beaumont/41/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
#* Notes from agenda points discussed&lt;br /&gt;
#*# Discuss whether voicemap API should be retained&lt;br /&gt;
#*#* [http://img.skitch.com/20070724-xwds1wnqbmhqrc93nuajrew7yc.jpg Only visual record of the voicemap]&lt;br /&gt;
#*#* An educated guess would be that the voicemap API was left online by accident when the voicemap page was taken down.&lt;br /&gt;
#*#* Response from [[User:Yoz Linden|Yoz]]:&amp;lt;blockquote style=&amp;quot;border:3px solid #666;background:#eee;&amp;quot;&amp;gt;&amp;lt;p&amp;gt;[02:49 PM]  Yoz Linden: OK, then we return to my original statement&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[02:49 PM]  Yoz Linden: namely, that you can use it as long as you want, but I wouldn&#039;t rely on it existing permanently&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
#*# Discuss desirable API calls&lt;br /&gt;
#*#* Monolithic dump of region data, similar to the one that used to be contained in slmapapi.js consisting of at least the region names &amp;amp; co-ordinates, with region uuid, [[Beta|server version/channel]], region owner UUID, and a list of viewer features requiring server-side support (as voice/display names/mesh etc. can be rolled out selectively)&lt;br /&gt;
#*#* Having region servers push a data dump off their parcel&#039;s metadata to an S3 server&lt;br /&gt;
#*#* API/feed of region movement/renaming&lt;br /&gt;
# Thursday 18th November 2010, 2pm-3pm SLT [http://mapapi.net/secondlife/Beaumont/41/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
#* Notes from agenda points discussed&lt;br /&gt;
#*# Request the LDPW to make available and maintain APIs for notable locations/landmarks (see http://mapapi.net/secondlife/ for example implementations of such APIs)&lt;br /&gt;
#*#* Request subsets of the monolithic dump be provided to indicate which mainland regions belong to each continent&lt;br /&gt;
#*#* Request for a LDPW category be added to the destination guide&lt;br /&gt;
#*#* Request the provision of pre-baked overlays showing road/rail routes, or more preferably, a list of co-ordinates indicating way points for such routes (see http://mapapi.net/_data/grid-configs/com/secondlife/agni/roads.js for the kind of data required to generate route overlays dynamically)&lt;br /&gt;
#*#* Request the provision of APIs/data dumps of &amp;quot;Large region names&amp;quot; for places such as &amp;quot;Snowlands&amp;quot; &amp;quot;Bay City&amp;quot; &amp;quot;Linden Village&amp;quot; &amp;quot;Vehicle Sandbox&amp;quot; etc&lt;br /&gt;
#*#* Request estate owners be given the option to &amp;quot;publish estate name&amp;quot;, so that the estate name for a region may be listed amongst the meta tags on world.secondlife.com/region/ documents.&lt;br /&gt;
# &amp;lt;del&amp;gt;Thursday 25th November 2010, 2pm-3pm SLT&amp;lt;/del&amp;gt; &amp;lt;ins&amp;gt;postponed until WEB-1560 gets processed&amp;lt;/ins&amp;gt; [http://mapapi.net/secondlife/Beaumont/41/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
#* Agenda&lt;br /&gt;
#*# Discuss desirable API calls&lt;br /&gt;
#*#* Desirable data in a per-region parcel data dump&lt;br /&gt;
#*# Discuss potential benefits of {{Jira|WEB-1560|WEB-1560: Apply a OSS license (BSD or GPL) to the SLURL.com JavaScript}}&lt;br /&gt;
#*#* See http://mapapi.net/secondlife/ for an example&lt;br /&gt;
[[Category: AW Groupies]]&lt;br /&gt;
[[Category:Map API VAG]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Map_API_VAG&amp;diff=1110932</id>
		<title>Map API VAG</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Map_API_VAG&amp;diff=1110932"/>
		<updated>2010-11-18T23:19:11Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: adding notes for items discussed, moving remaining items to next week&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;:this is an initial draft so scope and focus are still fairly open.  Please add comments to the [[{{TALKPAGENAME}}]] if you have slightly different viewpoints so we can try to converge on a common view. This discussion could also expose other similar VAG that are needed in this area&lt;br /&gt;
&lt;br /&gt;
The Map API Viewpoint Advocacy Group exists to ...  &lt;br /&gt;
&lt;br /&gt;
See the [[Architecture Working Group]] and the [[Viewpoint Advocacy Groups]] for more information.&lt;br /&gt;
&lt;br /&gt;
== Areas of concern addressed by the viewpoint ==&lt;br /&gt;
* Improving the usefulness of the Webmap API to both client, server and SL Viewer applications&lt;br /&gt;
* Permitting third-party developers to develop their own APIs by providing them with a data source suitable for updating their database&lt;br /&gt;
** Analysing use cases where the first party API is insufficient in order to improve the first party API&lt;br /&gt;
&lt;br /&gt;
== Source of Viewpoint ==&lt;br /&gt;
&lt;br /&gt;
== Use Cases ==&lt;br /&gt;
&lt;br /&gt;
See the [[Architecture Working Group Glossary]] and [[usecase templates]] for more information on creating usecases. One liners are fine (and better than nothing) but more detail will result in a better understanding and a better architecture.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Related JIRA Issues ==&lt;br /&gt;
The following JIRA issues are known problems that this VAG would like to see resolved in any future architecture.  The purpose of this list it to avoid problems that exist in the curent architecture. The more typical JIRAs that are more short term in nature or can be resolved by simple code or design change should not be listed here.&lt;br /&gt;
&lt;br /&gt;
* {{Jira|WEB-49}}, &#039;&#039;TSL lacks a Map API&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-87}} &#039;&#039;Webmap Images not updating&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-376}}, &#039;&#039;Map API does not properly handle SLPoint with region names&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-405}}, &#039;&#039;SLMAP API - disableVoiceInfo not working&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-473}}, &#039;&#039;webmap API indicates regions occupying multiple points in space simultaneously&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-474}}, &#039;&#039;Postcards need to send Global Coordinates since removal of SLPoint() from the SL Map API&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-503}}, &#039;&#039;sense; voice map API; it makes none, aka &amp;quot;query returns empty data set instead of error&#039;&#039;&lt;br /&gt;
* {{JIRA|WEB-504}}, &#039;&#039;PHP output mixed with javascript output&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* [http://secondlife.com/developers/mapapi/ Legacy Linden Lab API]&lt;br /&gt;
* [[Webmap API|current Linden Lab API]]&lt;br /&gt;
* [[User:SignpostMarv_Martin/Webmap_API]]&lt;br /&gt;
* [[User:Thraxis Epsilon/map_api|TMS Webmap API Proposal]]&lt;br /&gt;
* [http://blog.signpostmarv.name/2008/07/29/non-unique-region-names-within-the-confines-of-a-single-grid-yay-or-nay/ non-unique region names within the confines of a single grid, yay or nay ?]&lt;br /&gt;
&lt;br /&gt;
== Organization ==&lt;br /&gt;
Anyone with an interest in this Viewpoint is welcome to join. You should join the [[AW Groupies]] group in Second Life.&lt;br /&gt;
&lt;br /&gt;
=== Members (Stakeholders) ===&lt;br /&gt;
* [[User:SignpostMarv Martin|SignpostMarv Martin]]&lt;br /&gt;
* [[User:Hackshaven Harford|Hackshaven Harford]]&lt;br /&gt;
* [[User:Ice Brodie|Ice Brodie]] - Unable to make meeting on the 22nd&lt;br /&gt;
* [[User:Yoz Linden|Yoz Linden]]&lt;br /&gt;
* [[User:Thraxis Epsilon|Thraxis Epsilon]]&lt;br /&gt;
&lt;br /&gt;
=== In world meetings ===&lt;br /&gt;
&lt;br /&gt;
# [[Map API VAG/2008-01-22| Tuesday 22nd January 2008, 9:30am]] [http://slurl.com/secondlife/Beaumont/42/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
# Thursday 11th November 2010, 2pm [http://mapapi.net/secondlife/Beaumont/41/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
#* Notes from agenda points discussed&lt;br /&gt;
#*# Discuss whether voicemap API should be retained&lt;br /&gt;
#*#* [http://img.skitch.com/20070724-xwds1wnqbmhqrc93nuajrew7yc.jpg Only visual record of the voicemap]&lt;br /&gt;
#*#* An educated guess would be that the voicemap API was left online by accident when the voicemap page was taken down.&lt;br /&gt;
#*#* Response from [[User:Yoz Linden|Yoz]]:&amp;lt;blockquote style=&amp;quot;border:3px solid #666;background:#eee;&amp;quot;&amp;gt;&amp;lt;p&amp;gt;[02:49 PM]  Yoz Linden: OK, then we return to my original statement&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[02:49 PM]  Yoz Linden: namely, that you can use it as long as you want, but I wouldn&#039;t rely on it existing permanently&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
#*# Discuss desirable API calls&lt;br /&gt;
#*#* Monolithic dump of region data, similar to the one that used to be contained in slmapapi.js consisting of at least the region names &amp;amp; co-ordinates, with region uuid, [[Beta|server version/channel]], region owner UUID, and a list of viewer features requiring server-side support (as voice/display names/mesh etc. can be rolled out selectively)&lt;br /&gt;
#*#* Having region servers push a data dump off their parcel&#039;s metadata to an S3 server&lt;br /&gt;
#*#* API/feed of region movement/renaming&lt;br /&gt;
# Thursday 18th November 2010, 2pm-3pm SLT [http://mapapi.net/secondlife/Beaumont/41/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
#* Notes from agenda points discussed&lt;br /&gt;
#*# Request the LDPW to make available and maintain APIs for notable locations/landmarks (see http://mapapi.net/secondlife/ for example implementations of such APIs)&lt;br /&gt;
#*#* Request subsets of the monolithic dump be provided to indicate which mainland regions belong to each continent&lt;br /&gt;
#*#* Request for a LDPW category be added to the destination guide&lt;br /&gt;
#*#* Request the provision of pre-baked overlays showing road/rail routes, or more preferably, a list of co-ordinates indicating way points for such routes (see http://mapapi.net/_data/grid-configs/com/secondlife/agni/roads.js for the kind of data required to generate route overlays dynamically)&lt;br /&gt;
#*#* Request the provision of APIs/data dumps of &amp;quot;Large region names&amp;quot; for places such as &amp;quot;Snowlands&amp;quot; &amp;quot;Bay City&amp;quot; &amp;quot;Linden Village&amp;quot; &amp;quot;Vehicle Sandbox&amp;quot; etc&lt;br /&gt;
#*#* Request estate owners be given the option to &amp;quot;publish estate name&amp;quot;, so that the estate name for a region may be listed amongst the meta tags on world.secondlife.com/region/ documents.&lt;br /&gt;
# Thursday 25th November 2010, 2pm-3pm SLT [http://mapapi.net/secondlife/Beaumont/41/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
#* Agenda&lt;br /&gt;
#*# Discuss desirable API calls&lt;br /&gt;
#*#* Desirable data in a per-region parcel data dump&lt;br /&gt;
#*# Discuss potential benefits of {{Jira|WEB-1560|WEB-1560: Apply a OSS license (BSD or GPL) to the SLURL.com JavaScript}}&lt;br /&gt;
#*#* See http://mapapi.net/secondlife/ for an example&lt;br /&gt;
[[Category: AW Groupies]]&lt;br /&gt;
[[Category:Map API VAG]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Map_API_VAG&amp;diff=1105202</id>
		<title>Map API VAG</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Map_API_VAG&amp;diff=1105202"/>
		<updated>2010-11-14T05:48:20Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: /* In world meetings */ updating agenda, scheduling new meeting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;:this is an initial draft so scope and focus are still fairly open.  Please add comments to the [[{{TALKPAGENAME}}]] if you have slightly different viewpoints so we can try to converge on a common view. This discussion could also expose other similar VAG that are needed in this area&lt;br /&gt;
&lt;br /&gt;
The Map API Viewpoint Advocacy Group exists to ...  &lt;br /&gt;
&lt;br /&gt;
See the [[Architecture Working Group]] and the [[Viewpoint Advocacy Groups]] for more information.&lt;br /&gt;
&lt;br /&gt;
== Areas of concern addressed by the viewpoint ==&lt;br /&gt;
* Improving the usefulness of the Webmap API to both client, server and SL Viewer applications&lt;br /&gt;
* Permitting third-party developers to develop their own APIs by providing them with a data source suitable for updating their database&lt;br /&gt;
** Analysing use cases where the first party API is insufficient in order to improve the first party API&lt;br /&gt;
&lt;br /&gt;
== Source of Viewpoint ==&lt;br /&gt;
&lt;br /&gt;
== Use Cases ==&lt;br /&gt;
&lt;br /&gt;
See the [[Architecture Working Group Glossary]] and [[usecase templates]] for more information on creating usecases. One liners are fine (and better than nothing) but more detail will result in a better understanding and a better architecture.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Related JIRA Issues ==&lt;br /&gt;
The following JIRA issues are known problems that this VAG would like to see resolved in any future architecture.  The purpose of this list it to avoid problems that exist in the curent architecture. The more typical JIRAs that are more short term in nature or can be resolved by simple code or design change should not be listed here.&lt;br /&gt;
&lt;br /&gt;
* {{Jira|WEB-49}}, &#039;&#039;TSL lacks a Map API&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-87}} &#039;&#039;Webmap Images not updating&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-376}}, &#039;&#039;Map API does not properly handle SLPoint with region names&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-405}}, &#039;&#039;SLMAP API - disableVoiceInfo not working&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-473}}, &#039;&#039;webmap API indicates regions occupying multiple points in space simultaneously&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-474}}, &#039;&#039;Postcards need to send Global Coordinates since removal of SLPoint() from the SL Map API&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-503}}, &#039;&#039;sense; voice map API; it makes none, aka &amp;quot;query returns empty data set instead of error&#039;&#039;&lt;br /&gt;
* {{JIRA|WEB-504}}, &#039;&#039;PHP output mixed with javascript output&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* [http://secondlife.com/developers/mapapi/ Legacy Linden Lab API]&lt;br /&gt;
* [[Webmap API|current Linden Lab API]]&lt;br /&gt;
* [[User:SignpostMarv_Martin/Webmap_API]]&lt;br /&gt;
* [[User:Thraxis Epsilon/map_api|TMS Webmap API Proposal]]&lt;br /&gt;
* [http://blog.signpostmarv.name/2008/07/29/non-unique-region-names-within-the-confines-of-a-single-grid-yay-or-nay/ non-unique region names within the confines of a single grid, yay or nay ?]&lt;br /&gt;
&lt;br /&gt;
== Organization ==&lt;br /&gt;
Anyone with an interest in this Viewpoint is welcome to join. You should join the [[AW Groupies]] group in Second Life.&lt;br /&gt;
&lt;br /&gt;
=== Members (Stakeholders) ===&lt;br /&gt;
* [[User:SignpostMarv Martin|SignpostMarv Martin]]&lt;br /&gt;
* [[User:Hackshaven Harford|Hackshaven Harford]]&lt;br /&gt;
* [[User:Ice Brodie|Ice Brodie]] - Unable to make meeting on the 22nd&lt;br /&gt;
* [[User:Yoz Linden|Yoz Linden]]&lt;br /&gt;
* [[User:Thraxis Epsilon|Thraxis Epsilon]]&lt;br /&gt;
&lt;br /&gt;
=== In world meetings ===&lt;br /&gt;
&lt;br /&gt;
# [[Map API VAG/2008-01-22| Tuesday 22nd January 2008, 9:30am]] [http://slurl.com/secondlife/Beaumont/42/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
# Thursday 11th November 2010, 2pm [http://mapapi.net/secondlife/Beaumont/41/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
#* Notes from agenda points discussed&lt;br /&gt;
#*# Discuss whether voicemap API should be retained&lt;br /&gt;
#*#* [http://img.skitch.com/20070724-xwds1wnqbmhqrc93nuajrew7yc.jpg Only visual record of the voicemap]&lt;br /&gt;
#*#* An educated guess would be that the voicemap API was left online by accident when the voicemap page was taken down.&lt;br /&gt;
#*#* Response from [[User:Yoz Linden|Yoz]]:&amp;lt;blockquote style=&amp;quot;border:3px solid #666;background:#eee;&amp;quot;&amp;gt;&amp;lt;p&amp;gt;[02:49 PM]  Yoz Linden: OK, then we return to my original statement&amp;lt;/p&amp;gt;&amp;lt;p&amp;gt;[02:49 PM]  Yoz Linden: namely, that you can use it as long as you want, but I wouldn&#039;t rely on it existing permanently&amp;lt;/p&amp;gt;&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
#*# Discuss desirable API calls&lt;br /&gt;
#*#* Monolithic dump of region data, similar to the one that used to be contained in slmapapi.js consisting of at least the region names &amp;amp; co-ordinates, with region uuid, [[Beta|server version/channel]], region owner UUID, and a list of viewer features requiring server-side support (as voice/display names/mesh etc. can be rolled out selectively)&lt;br /&gt;
#*#* Having region servers push a data dump off their parcel&#039;s metadata to an S3 server&lt;br /&gt;
#*#* API/feed of region movement/renaming&lt;br /&gt;
# Thursday 18th November 2010, 2pm-3pm SLT [http://mapapi.net/secondlife/Beaumont/41/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
#* Agenda&lt;br /&gt;
#*# Discuss desirable API calls&lt;br /&gt;
#*#* Desirable data in a per-region parcel data dump&lt;br /&gt;
#*#* Request the LDPW to make available and maintain APIs for notable locations/landmarks (see http://mapapi.net/secondlife/ for example implementations of such APIs)&lt;br /&gt;
#*# Discuss potential benefits of {{Jira|WEB-1560|WEB-1560: Apply a OSS license (BSD or GPL) to the SLURL.com JavaScript}} (moved from previous meeting)&lt;br /&gt;
#*#* See http://mapapi.net/secondlife/ for an example&lt;br /&gt;
[[Category: AW Groupies]]&lt;br /&gt;
[[Category:Map API VAG]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Map_API_VAG&amp;diff=1095852</id>
		<title>Map API VAG</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Map_API_VAG&amp;diff=1095852"/>
		<updated>2010-11-08T00:49:50Z</updated>

		<summary type="html">&lt;p&gt;SignpostMarv Martin: /* Organization */  shuffling sections about&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;:this is an initial draft so scope and focus are still fairly open.  Please add comments to the [[{{TALKPAGENAME}}]] if you have slightly different viewpoints so we can try to converge on a common view. This discussion could also expose other similar VAG that are needed in this area&lt;br /&gt;
&lt;br /&gt;
The Map API Viewpoint Advocacy Group exists to ...  &lt;br /&gt;
&lt;br /&gt;
See the [[Architecture Working Group]] and the [[Viewpoint Advocacy Groups]] for more information.&lt;br /&gt;
&lt;br /&gt;
== Areas of concern addressed by the viewpoint ==&lt;br /&gt;
* Improving the usefulness of the Webmap API to both client, server and SL Viewer applications&lt;br /&gt;
* Permitting third-party developers to develop their own APIs by providing them with a data source suitable for updating their database&lt;br /&gt;
** Analysing use cases where the first party API is insufficient in order to improve the first party API&lt;br /&gt;
&lt;br /&gt;
== Source of Viewpoint ==&lt;br /&gt;
&lt;br /&gt;
== Use Cases ==&lt;br /&gt;
&lt;br /&gt;
See the [[Architecture Working Group Glossary]] and [[usecase templates]] for more information on creating usecases. One liners are fine (and better than nothing) but more detail will result in a better understanding and a better architecture.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Related JIRA Issues ==&lt;br /&gt;
The following JIRA issues are known problems that this VAG would like to see resolved in any future architecture.  The purpose of this list it to avoid problems that exist in the curent architecture. The more typical JIRAs that are more short term in nature or can be resolved by simple code or design change should not be listed here.&lt;br /&gt;
&lt;br /&gt;
* {{Jira|WEB-49}}, &#039;&#039;TSL lacks a Map API&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-87}} &#039;&#039;Webmap Images not updating&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-376}}, &#039;&#039;Map API does not properly handle SLPoint with region names&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-405}}, &#039;&#039;SLMAP API - disableVoiceInfo not working&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-473}}, &#039;&#039;webmap API indicates regions occupying multiple points in space simultaneously&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-474}}, &#039;&#039;Postcards need to send Global Coordinates since removal of SLPoint() from the SL Map API&#039;&#039;&lt;br /&gt;
* {{Jira|WEB-503}}, &#039;&#039;sense; voice map API; it makes none, aka &amp;quot;query returns empty data set instead of error&#039;&#039;&lt;br /&gt;
* {{JIRA|WEB-504}}, &#039;&#039;PHP output mixed with javascript output&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
* [http://secondlife.com/developers/mapapi/ Legacy Linden Lab API]&lt;br /&gt;
* [[Webmap API|current Linden Lab API]]&lt;br /&gt;
* [[User:SignpostMarv_Martin/Webmap_API]]&lt;br /&gt;
* [[User:Thraxis Epsilon/map_api|TMS Webmap API Proposal]]&lt;br /&gt;
* [http://blog.signpostmarv.name/2008/07/29/non-unique-region-names-within-the-confines-of-a-single-grid-yay-or-nay/ non-unique region names within the confines of a single grid, yay or nay ?]&lt;br /&gt;
&lt;br /&gt;
== Organization ==&lt;br /&gt;
Anyone with an interest in this Viewpoint is welcome to join. You should join the [[AW Groupies]] group in Second Life.&lt;br /&gt;
&lt;br /&gt;
=== Members (Stakeholders) ===&lt;br /&gt;
* [[User:SignpostMarv Martin|SignpostMarv Martin]]&lt;br /&gt;
* [[User:Hackshaven Harford|Hackshaven Harford]]&lt;br /&gt;
* [[User:Ice Brodie|Ice Brodie]] - Unable to make meeting on the 22nd&lt;br /&gt;
* [[User:Yoz Linden|Yoz Linden]]&lt;br /&gt;
* [[User:Thraxis Epsilon|Thraxis Epsilon]]&lt;br /&gt;
&lt;br /&gt;
=== In world meetings ===&lt;br /&gt;
&lt;br /&gt;
# [[Map API VAG/2008-01-22| Tuesday 22nd January 2008, 9:30am]] [http://slurl.com/secondlife/Beaumont/42/218/35 Meta Linden&#039;s Office]&lt;br /&gt;
# Thursday 11th November 2010, 2pm (location undecided)&lt;br /&gt;
#* Agenda&lt;br /&gt;
#*# Discuss whether voicemap API should be retained&lt;br /&gt;
#*# Discuss desirable API calls&lt;br /&gt;
#*# Discuss potential benefits of {{Jira|WEB-1560|WEB-1560: Apply a OSS license (BSD or GPL) to the SLURL.com JavaScript}}&lt;br /&gt;
#*#* See http://mapapi.net/secondlife/ for an example&lt;br /&gt;
&lt;br /&gt;
[[Category: AW Groupies]]&lt;br /&gt;
[[Category:Map API VAG]]&lt;/div&gt;</summary>
		<author><name>SignpostMarv Martin</name></author>
	</entry>
</feed>