<?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=Phoenix+Linden</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=Phoenix+Linden"/>
	<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/wiki/Special:Contributions/Phoenix_Linden"/>
	<updated>2026-07-28T07:39:11Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Texture_meta-data&amp;diff=433613</id>
		<title>Texture meta-data</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Texture_meta-data&amp;diff=433613"/>
		<updated>2009-07-17T20:14:39Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: Created page with &amp;#039;On upload, [http://www.jpeg.org/public/fcd15444-1.pdf j2c textures] will have all CME segments in the main header removed to be replaced by a single CME segment. That segment wil...&amp;#039;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;On upload, [http://www.jpeg.org/public/fcd15444-1.pdf j2c textures] will have all CME segments in the main header removed to be replaced by a single CME segment. That segment will be serialized as an unordered key-value url query string with the following keys and associated values.&lt;br /&gt;
&lt;br /&gt;
;a:The agent_id of the resident that uploaded the texture.&lt;br /&gt;
;z:The utc time the texture was uploaded in &#039;&#039;&#039;YYYYmmddHHMMSS&#039;&#039;&#039; [http://www.python.org/doc/2.5.2/lib/module-time.html format].&lt;br /&gt;
;w:The original width of the image as reported by the viewer. This value must be interpretable as an integer greater than 0 and less than 1,000,000.&lt;br /&gt;
;h:The original height of the image as reported by the viewer. This value must be interpretable as an integer greater than 0 and less than 1,000,000.&lt;br /&gt;
;c:The average color of the image as calculated during verification. The value will be &#039;&#039;&#039;RRGGBBAA&#039;&#039;&#039; in hex with 00 being none and ff representing full saturation of that component. If the image only has three components, then alpha is set to ff. If there are more than four components, the extra components are skipped. &lt;br /&gt;
&lt;br /&gt;
== example ==&lt;br /&gt;
The actual encoded comment string will look something like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
a=abbee3b5-fbe0-4cfa-8d15-323d6800448e&amp;amp;h=480&amp;amp;w=640&amp;amp;z=20081118204138&amp;amp;c=26961aff&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== tool support ==&lt;br /&gt;
The &amp;lt;code&amp;gt;j2c_comments.py&amp;lt;/code&amp;gt; script understands j2c codestream CME markers and will parse for them in the main header. To use it, pass a list of j2c codestream file names on the command line. The script will emit the file name parsed and report on comments found for each. If the example above is in test.texture, the session would look something like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ ./j2c_comments.py test.texture&lt;br /&gt;
test.texture: {&lt;br /&gt;
  &#039;a&#039;:[&#039;abbee3b5-fbe0-4cfa-8d15-323d6800448e&#039;], &lt;br /&gt;
  &#039;h&#039;:[&#039;480&#039;],&lt;br /&gt;
  &#039;w&#039;:[&#039;640&#039;],&lt;br /&gt;
  &#039;z&#039;:[&#039;20081118204138&#039;],&lt;br /&gt;
  &#039;c&#039;:[&#039;26961aff&#039;]}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The tool will emit error messages if the codestream could not be understood, or if the comment is not latin1. Comments which do not conform to the query string format will be treated as a plain, raw latin1 string.&lt;br /&gt;
&lt;br /&gt;
=== j2c_comments.py ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
#!/usr/bin/env python&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
Extract out all of the j2c CME markers&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
import cgi&lt;br /&gt;
import optparse&lt;br /&gt;
import struct&lt;br /&gt;
&lt;br /&gt;
class NotJ2C(Exception):&lt;br /&gt;
    pass&lt;br /&gt;
&lt;br /&gt;
def parse_cme(filename):&lt;br /&gt;
    j2c = file(filename, &#039;rb&#039;)&lt;br /&gt;
    comments = None&lt;br /&gt;
    while True:&lt;br /&gt;
        marker_bytes = j2c.read(2)&lt;br /&gt;
        marker, marker_type = struct.unpack(&#039;BB&#039;, marker_bytes)&lt;br /&gt;
        if marker != 0xff:&lt;br /&gt;
            raise NotJ2C&lt;br /&gt;
        if marker_type == 0x90:&lt;br /&gt;
            # we found the SOT, so we&#039;re done.&lt;br /&gt;
            return comments&lt;br /&gt;
        elif marker_type == 0x4f:&lt;br /&gt;
            # this is SOC, which does not have a lsoc element&lt;br /&gt;
            continue&lt;br /&gt;
        size_bytes = j2c.read(2)&lt;br /&gt;
        size = struct.unpack(&#039;!H&#039;, size_bytes)[0] - 2&lt;br /&gt;
&lt;br /&gt;
        if marker_type == 0x64:&lt;br /&gt;
            # found a CME. read it, and interpret it.&lt;br /&gt;
            rcme = j2c.read(2)&lt;br /&gt;
            rcme = struct.unpack(&#039;!H&#039;, rcme)[0]&lt;br /&gt;
            if rcme == 0:&lt;br /&gt;
                new_comment = &#039;&amp;lt;binary&amp;gt;&#039;&lt;br /&gt;
            elif rcme == 1:&lt;br /&gt;
                raw_comment = j2c.read(size - 2)&lt;br /&gt;
                new_comment = cgi.parse_qs(raw_comment)&lt;br /&gt;
                if len(new_comment) == 0:&lt;br /&gt;
                    new_comment = raw_comment&lt;br /&gt;
            else:&lt;br /&gt;
                new_comment = &#039;&amp;lt;unknown&amp;gt;&#039;&lt;br /&gt;
&lt;br /&gt;
            if comments is None:&lt;br /&gt;
                comments = new_comment&lt;br /&gt;
            elif type(comments) == &#039;list&#039;:&lt;br /&gt;
                comments.append(new_comment)&lt;br /&gt;
            else:&lt;br /&gt;
                comments = [comments, new_comments]&lt;br /&gt;
            continue&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
        j2c.seek(size, 1)&lt;br /&gt;
        continue&lt;br /&gt;
&lt;br /&gt;
def main():&lt;br /&gt;
    parser = optparse.OptionParser(&lt;br /&gt;
        usage=&amp;quot;usage: %prog [options] file_list&amp;quot;,&lt;br /&gt;
        description=&amp;quot;Read through file list and extract the CME field&amp;quot;)&lt;br /&gt;
    options, args = parser.parse_args()&lt;br /&gt;
    if len(args) &amp;lt; 1:&lt;br /&gt;
        parser.error(&amp;quot;Please specify one or more files to assign.&amp;quot;)&lt;br /&gt;
    for filename in args:&lt;br /&gt;
        try:&lt;br /&gt;
            comments = parse_cme(filename)&lt;br /&gt;
            print filename + &#039;: &#039; + str(comments)&lt;br /&gt;
        except NotJ2C:&lt;br /&gt;
            print filename + &#039;: Unable to parse file&#039;&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    main()&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Assets]]&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Textures_(OS)&amp;diff=433603</id>
		<title>Textures (OS)</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Textures_(OS)&amp;diff=433603"/>
		<updated>2009-07-17T20:11:07Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* Functional Spec */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{OSWikiFeatureNav}}&lt;br /&gt;
=== Feature Design Document ===&lt;br /&gt;
(none)&lt;br /&gt;
&lt;br /&gt;
=== Functional Spec ===&lt;br /&gt;
File format details are available in annex A of [http://www.jpeg.org/public/fcd15444-1.pdf JPEG 2000 Part I Final Committee Draft Version 1.0].&lt;br /&gt;
&lt;br /&gt;
Second Life treats jpeg 2000 codestreams as MIME type image/x-j2c. The image/j2c MIME type include extra packing data which was not finalized when Second Life first opened.&lt;br /&gt;
&lt;br /&gt;
As of version 1.27 of the Second Life server, uploaded textures contain [[texture meta-data]] in the jpeg 2000 CME sections.&lt;br /&gt;
&lt;br /&gt;
=== Test scripts ===&lt;br /&gt;
[[Texture Test]]&lt;br /&gt;
&lt;br /&gt;
[[Edit Object Texture Test]]&lt;br /&gt;
&lt;br /&gt;
[https://osiris.lindenlab.com/mediawiki/index.php/Texture_Pipeline_Performance_test Texture_Pipeline_Performance_test internal test]&lt;br /&gt;
&lt;br /&gt;
[https://osiris.lindenlab.com/mediawiki/index.php/Texture_Pipeline_Quality_test Texture_Pipeline_Quality_test internal test]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Discussion for future improvements ===&lt;br /&gt;
[[Texture Console]]&lt;br /&gt;
&lt;br /&gt;
=== Relationship to other features ===&lt;br /&gt;
&amp;lt;b&amp;gt; List of features that need to be tested when this feature changes, and why. &amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[https://osiris.lindenlab.com/mediawiki/index.php/Render_Performance_Test internal test]&lt;br /&gt;
&lt;br /&gt;
[[Uploading Assets]] - You can only upload textures of a certain format and size.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== User Guides ===&lt;br /&gt;
* [http://robinwood.com/Catalog/Technical/SL-Tuts/SLTutSet.html Texture Tutorials by Robin Sojourner]&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Patch_TUT&amp;diff=417023</id>
		<title>Patch TUT</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Patch_TUT&amp;diff=417023"/>
		<updated>2009-06-29T17:27:10Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* TUT-2008-11-30 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Our unit test framework did not have any method for skipping tests. Sometimes known failure cases are found which require temporarily skipping tests. This patch adds that functionality.&lt;br /&gt;
&lt;br /&gt;
= TUT-2006-11-04 =&lt;br /&gt;
&#039;&#039;&#039;WARNING&#039;&#039;&#039;: This is a patch to a pretty old version of tut, but currently the version in use.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--- tut-orig/tut.h	2007-05-23 16:37:00.000000000 -0700&lt;br /&gt;
+++ tut-new/tut.h	2007-05-23 16:40:18.000000000 -0700&lt;br /&gt;
@@ -79,6 +79,15 @@&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
   /**&lt;br /&gt;
+   * Exception to be throwed when skip_fail() is called.&lt;br /&gt;
+   */&lt;br /&gt;
+  class skip_failure : public std::logic_error&lt;br /&gt;
+  {&lt;br /&gt;
+    public:&lt;br /&gt;
+      skip_failure(const std::string&amp;amp; msg) : std::logic_error(msg){};&lt;br /&gt;
+  };&lt;br /&gt;
+&lt;br /&gt;
+  /**&lt;br /&gt;
    * Exception to be throwed when test desctructor throwed an exception.&lt;br /&gt;
    */&lt;br /&gt;
   class warning : public std::logic_error&lt;br /&gt;
@@ -120,8 +129,20 @@&lt;br /&gt;
      * ex - test throwed an exceptions&lt;br /&gt;
      * warn - test finished successfully, but test destructor throwed&lt;br /&gt;
      * term - test forced test application to terminate abnormally&lt;br /&gt;
+     * skip - test skipped&lt;br /&gt;
+     * skip_fail - test skpped because it is a known failure case&lt;br /&gt;
      */&lt;br /&gt;
-    typedef enum { ok, fail, ex, warn, term, ex_ctor } result_type;&lt;br /&gt;
+    typedef enum&lt;br /&gt;
+	{&lt;br /&gt;
+		ok,&lt;br /&gt;
+		fail,&lt;br /&gt;
+		ex,&lt;br /&gt;
+		warn,&lt;br /&gt;
+		term,&lt;br /&gt;
+		ex_ctor,&lt;br /&gt;
+		skip,&lt;br /&gt;
+		skip_fail,&lt;br /&gt;
+	} result_type;&lt;br /&gt;
     result_type result;&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
@@ -168,7 +189,7 @@&lt;br /&gt;
&lt;br /&gt;
     // execute tests iteratively&lt;br /&gt;
     virtual void rewind() = 0;&lt;br /&gt;
-    virtual test_result run_next() = 0;&lt;br /&gt;
+    virtual test_result run_next(int skip_test_id = 0) = 0;&lt;br /&gt;
&lt;br /&gt;
     // execute one test&lt;br /&gt;
     virtual test_result run_test(int n) = 0;&lt;br /&gt;
@@ -316,7 +337,7 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Runs all tests in specified group.&lt;br /&gt;
      */&lt;br /&gt;
-    void run_tests(const std::string&amp;amp; group_name) const&lt;br /&gt;
+    void run_tests(const std::string&amp;amp; group_name, int skip_test_id = 0) const&lt;br /&gt;
     {&lt;br /&gt;
       callback_-&amp;gt;run_started();&lt;br /&gt;
&lt;br /&gt;
@@ -328,7 +349,7 @@&lt;br /&gt;
&lt;br /&gt;
       try&lt;br /&gt;
       {&lt;br /&gt;
-        run_all_tests_in_group_(i);&lt;br /&gt;
+        run_all_tests_in_group_(i, skip_test_id);&lt;br /&gt;
       }&lt;br /&gt;
       catch( const no_more_tests&amp;amp; )&lt;br /&gt;
       {&lt;br /&gt;
@@ -371,12 +392,13 @@&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     private:&lt;br /&gt;
-    void run_all_tests_in_group_(const_iterator i) const&lt;br /&gt;
+    void run_all_tests_in_group_(const_iterator i, int skip_test_id = 0) const&lt;br /&gt;
     {&lt;br /&gt;
       i-&amp;gt;second-&amp;gt;rewind();&lt;br /&gt;
       for( ;; )&lt;br /&gt;
       {&lt;br /&gt;
-        test_result tr = i-&amp;gt;second-&amp;gt;run_next();&lt;br /&gt;
+        test_result tr = i-&amp;gt;second-&amp;gt;run_next(skip_test_id);&lt;br /&gt;
+&lt;br /&gt;
         callback_-&amp;gt;test_completed(tr);&lt;br /&gt;
&lt;br /&gt;
 	if( tr.result == test_result::ex_ctor )&lt;br /&gt;
@@ -436,13 +458,11 @@&lt;br /&gt;
     }&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
-  namespace &lt;br /&gt;
-  {&lt;br /&gt;
     /**&lt;br /&gt;
      * Tests provided condition.&lt;br /&gt;
      * Throws if false.&lt;br /&gt;
      */&lt;br /&gt;
-    void ensure(bool cond)&lt;br /&gt;
+    inline void ensure(bool cond)&lt;br /&gt;
     {&lt;br /&gt;
        if( !cond ) throw failure(&amp;quot;&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
@@ -511,10 +531,19 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Unconditionally fails with message.&lt;br /&gt;
      */&lt;br /&gt;
-    void fail(const char* msg=&amp;quot;&amp;quot;)&lt;br /&gt;
+	template &amp;lt;class T&amp;gt;&lt;br /&gt;
+    void fail(const T msg)&lt;br /&gt;
     {&lt;br /&gt;
       throw failure(msg);&lt;br /&gt;
     }&lt;br /&gt;
+&lt;br /&gt;
+    /**&lt;br /&gt;
+     * Unconditionally fails with message.&lt;br /&gt;
+     */&lt;br /&gt;
+	template &amp;lt;class T&amp;gt;&lt;br /&gt;
+    void skip_fail(const T msg)&lt;br /&gt;
+    {&lt;br /&gt;
+      throw skip_failure(msg);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   /**&lt;br /&gt;
@@ -705,7 +734,7 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Runs next test.&lt;br /&gt;
      */&lt;br /&gt;
-    test_result run_next()&lt;br /&gt;
+    test_result run_next(int skip_test_id = 0)&lt;br /&gt;
     {&lt;br /&gt;
       if( current_test_ == tests_.end() )&lt;br /&gt;
       {&lt;br /&gt;
@@ -718,8 +747,17 @@&lt;br /&gt;
       {&lt;br /&gt;
         try&lt;br /&gt;
         {&lt;br /&gt;
+          if (current_test_-&amp;gt;first == skip_test_id)&lt;br /&gt;
+          {&lt;br /&gt;
+              test_result tr(name_,current_test_-&amp;gt;first,test_result::skip);&lt;br /&gt;
+              current_test_++;&lt;br /&gt;
+              return tr;&lt;br /&gt;
+          }&lt;br /&gt;
+          else&lt;br /&gt;
+          {&lt;br /&gt;
           return run_test_(current_test_++,obj);&lt;br /&gt;
         }&lt;br /&gt;
+        }&lt;br /&gt;
         catch( const no_such_test&amp;amp; )&lt;br /&gt;
         {&lt;br /&gt;
           continue; &lt;br /&gt;
@@ -774,6 +812,12 @@&lt;br /&gt;
         test_result tr(name_,ti-&amp;gt;first,test_result::fail,ex);&lt;br /&gt;
         return tr;&lt;br /&gt;
       }&lt;br /&gt;
+      catch(const skip_failure&amp;amp; ex)&lt;br /&gt;
+      {&lt;br /&gt;
+        // test failed because of ensure() or similar method&lt;br /&gt;
+        test_result tr(name_,ti-&amp;gt;first,test_result::skip_fail,ex);&lt;br /&gt;
+        return tr;&lt;br /&gt;
+      }&lt;br /&gt;
       catch(const seh&amp;amp; ex)&lt;br /&gt;
       {&lt;br /&gt;
         // test failed with sigsegv, divide by zero, etc&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Save this patch as tut.patch in the same directory as tut.h and apply it from a terminal program like xterm or cygwin with the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ patch -p1 &amp;lt; tut.patch&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TUT-2008-11-30 =&lt;br /&gt;
Internally, TUT has been migrated to the 2008-11-30. This patch will not work against the current code, but is expected to be in use soon.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--- tut.orig/tut_assert.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_assert.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -154,9 +154,23 @@&lt;br /&gt;
     throw failure(msg);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
+/**&lt;br /&gt;
+ * Skip test because of known failure.&lt;br /&gt;
+ */&lt;br /&gt;
+void skip(const char* msg = &amp;quot;&amp;quot;)&lt;br /&gt;
+{&lt;br /&gt;
+    throw skip_failure(msg);&lt;br /&gt;
+}&lt;br /&gt;
+&lt;br /&gt;
+void skip(const std::string&amp;amp; msg)&lt;br /&gt;
+{&lt;br /&gt;
+    throw skip_failure(msg);&lt;br /&gt;
+}&lt;br /&gt;
+&lt;br /&gt;
 } // end of namespace&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
+&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
diff -u tut.orig/tut_exception.hpp tut.new/tut_exception.hpp&lt;br /&gt;
--- tut.orig/tut_exception.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_exception.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -201,6 +201,26 @@&lt;br /&gt;
     const test_result tr;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
+/**&lt;br /&gt;
+ * Exception to be throwed when skip_fail() is called.&lt;br /&gt;
+ */&lt;br /&gt;
+struct skip_failure : public failure&lt;br /&gt;
+{&lt;br /&gt;
+    skip_failure(const std::string&amp;amp; msg) &lt;br /&gt;
+        : failure(msg) &lt;br /&gt;
+    {&lt;br /&gt;
+    }&lt;br /&gt;
+&lt;br /&gt;
+    test_result::result_type result() const&lt;br /&gt;
+    {&lt;br /&gt;
+        return test_result::skip;&lt;br /&gt;
+    }&lt;br /&gt;
+&lt;br /&gt;
+    ~skip_failure() throw()&lt;br /&gt;
+    {&lt;br /&gt;
+    }&lt;br /&gt;
+};&lt;br /&gt;
+&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
diff -u tut.orig/tut_result.hpp tut.new/tut_result.hpp&lt;br /&gt;
--- tut.orig/tut_result.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_result.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -51,6 +51,7 @@&lt;br /&gt;
      * ex - test throwed an exceptions&lt;br /&gt;
      * warn - test finished successfully, but test destructor throwed&lt;br /&gt;
      * term - test forced test application to terminate abnormally&lt;br /&gt;
+     * skip - test skpped because it is a known failure case&lt;br /&gt;
      */&lt;br /&gt;
     enum result_type&lt;br /&gt;
     {&lt;br /&gt;
@@ -60,7 +61,8 @@&lt;br /&gt;
         warn,&lt;br /&gt;
         term,&lt;br /&gt;
         ex_ctor,&lt;br /&gt;
-        rethrown&lt;br /&gt;
+        rethrown,&lt;br /&gt;
+        skip,&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     result_type result;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save this patch as &amp;lt;code&amp;gt;tut.patch&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;tut-2008-11-30/tut&amp;lt;/code&amp;gt; directory - alongside the &amp;lt;code&amp;gt;tut_assert.hpp&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;tut_exception.hpp&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;tut_result.hpp&amp;lt;/code&amp;gt; files - and apply it from a terminal program like xterm or cygwin with the command: &lt;br /&gt;
&lt;br /&gt;
  $ patch -p1 &amp;lt; tut.patch&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Patch_TUT&amp;diff=417013</id>
		<title>Patch TUT</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Patch_TUT&amp;diff=417013"/>
		<updated>2009-06-29T17:25:50Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* TUT-2008-11-30 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Our unit test framework did not have any method for skipping tests. Sometimes known failure cases are found which require temporarily skipping tests. This patch adds that functionality.&lt;br /&gt;
&lt;br /&gt;
= TUT-2006-11-04 =&lt;br /&gt;
&#039;&#039;&#039;WARNING&#039;&#039;&#039;: This is a patch to a pretty old version of tut, but currently the version in use.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--- tut-orig/tut.h	2007-05-23 16:37:00.000000000 -0700&lt;br /&gt;
+++ tut-new/tut.h	2007-05-23 16:40:18.000000000 -0700&lt;br /&gt;
@@ -79,6 +79,15 @@&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
   /**&lt;br /&gt;
+   * Exception to be throwed when skip_fail() is called.&lt;br /&gt;
+   */&lt;br /&gt;
+  class skip_failure : public std::logic_error&lt;br /&gt;
+  {&lt;br /&gt;
+    public:&lt;br /&gt;
+      skip_failure(const std::string&amp;amp; msg) : std::logic_error(msg){};&lt;br /&gt;
+  };&lt;br /&gt;
+&lt;br /&gt;
+  /**&lt;br /&gt;
    * Exception to be throwed when test desctructor throwed an exception.&lt;br /&gt;
    */&lt;br /&gt;
   class warning : public std::logic_error&lt;br /&gt;
@@ -120,8 +129,20 @@&lt;br /&gt;
      * ex - test throwed an exceptions&lt;br /&gt;
      * warn - test finished successfully, but test destructor throwed&lt;br /&gt;
      * term - test forced test application to terminate abnormally&lt;br /&gt;
+     * skip - test skipped&lt;br /&gt;
+     * skip_fail - test skpped because it is a known failure case&lt;br /&gt;
      */&lt;br /&gt;
-    typedef enum { ok, fail, ex, warn, term, ex_ctor } result_type;&lt;br /&gt;
+    typedef enum&lt;br /&gt;
+	{&lt;br /&gt;
+		ok,&lt;br /&gt;
+		fail,&lt;br /&gt;
+		ex,&lt;br /&gt;
+		warn,&lt;br /&gt;
+		term,&lt;br /&gt;
+		ex_ctor,&lt;br /&gt;
+		skip,&lt;br /&gt;
+		skip_fail,&lt;br /&gt;
+	} result_type;&lt;br /&gt;
     result_type result;&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
@@ -168,7 +189,7 @@&lt;br /&gt;
&lt;br /&gt;
     // execute tests iteratively&lt;br /&gt;
     virtual void rewind() = 0;&lt;br /&gt;
-    virtual test_result run_next() = 0;&lt;br /&gt;
+    virtual test_result run_next(int skip_test_id = 0) = 0;&lt;br /&gt;
&lt;br /&gt;
     // execute one test&lt;br /&gt;
     virtual test_result run_test(int n) = 0;&lt;br /&gt;
@@ -316,7 +337,7 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Runs all tests in specified group.&lt;br /&gt;
      */&lt;br /&gt;
-    void run_tests(const std::string&amp;amp; group_name) const&lt;br /&gt;
+    void run_tests(const std::string&amp;amp; group_name, int skip_test_id = 0) const&lt;br /&gt;
     {&lt;br /&gt;
       callback_-&amp;gt;run_started();&lt;br /&gt;
&lt;br /&gt;
@@ -328,7 +349,7 @@&lt;br /&gt;
&lt;br /&gt;
       try&lt;br /&gt;
       {&lt;br /&gt;
-        run_all_tests_in_group_(i);&lt;br /&gt;
+        run_all_tests_in_group_(i, skip_test_id);&lt;br /&gt;
       }&lt;br /&gt;
       catch( const no_more_tests&amp;amp; )&lt;br /&gt;
       {&lt;br /&gt;
@@ -371,12 +392,13 @@&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     private:&lt;br /&gt;
-    void run_all_tests_in_group_(const_iterator i) const&lt;br /&gt;
+    void run_all_tests_in_group_(const_iterator i, int skip_test_id = 0) const&lt;br /&gt;
     {&lt;br /&gt;
       i-&amp;gt;second-&amp;gt;rewind();&lt;br /&gt;
       for( ;; )&lt;br /&gt;
       {&lt;br /&gt;
-        test_result tr = i-&amp;gt;second-&amp;gt;run_next();&lt;br /&gt;
+        test_result tr = i-&amp;gt;second-&amp;gt;run_next(skip_test_id);&lt;br /&gt;
+&lt;br /&gt;
         callback_-&amp;gt;test_completed(tr);&lt;br /&gt;
&lt;br /&gt;
 	if( tr.result == test_result::ex_ctor )&lt;br /&gt;
@@ -436,13 +458,11 @@&lt;br /&gt;
     }&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
-  namespace &lt;br /&gt;
-  {&lt;br /&gt;
     /**&lt;br /&gt;
      * Tests provided condition.&lt;br /&gt;
      * Throws if false.&lt;br /&gt;
      */&lt;br /&gt;
-    void ensure(bool cond)&lt;br /&gt;
+    inline void ensure(bool cond)&lt;br /&gt;
     {&lt;br /&gt;
        if( !cond ) throw failure(&amp;quot;&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
@@ -511,10 +531,19 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Unconditionally fails with message.&lt;br /&gt;
      */&lt;br /&gt;
-    void fail(const char* msg=&amp;quot;&amp;quot;)&lt;br /&gt;
+	template &amp;lt;class T&amp;gt;&lt;br /&gt;
+    void fail(const T msg)&lt;br /&gt;
     {&lt;br /&gt;
       throw failure(msg);&lt;br /&gt;
     }&lt;br /&gt;
+&lt;br /&gt;
+    /**&lt;br /&gt;
+     * Unconditionally fails with message.&lt;br /&gt;
+     */&lt;br /&gt;
+	template &amp;lt;class T&amp;gt;&lt;br /&gt;
+    void skip_fail(const T msg)&lt;br /&gt;
+    {&lt;br /&gt;
+      throw skip_failure(msg);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   /**&lt;br /&gt;
@@ -705,7 +734,7 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Runs next test.&lt;br /&gt;
      */&lt;br /&gt;
-    test_result run_next()&lt;br /&gt;
+    test_result run_next(int skip_test_id = 0)&lt;br /&gt;
     {&lt;br /&gt;
       if( current_test_ == tests_.end() )&lt;br /&gt;
       {&lt;br /&gt;
@@ -718,8 +747,17 @@&lt;br /&gt;
       {&lt;br /&gt;
         try&lt;br /&gt;
         {&lt;br /&gt;
+          if (current_test_-&amp;gt;first == skip_test_id)&lt;br /&gt;
+          {&lt;br /&gt;
+              test_result tr(name_,current_test_-&amp;gt;first,test_result::skip);&lt;br /&gt;
+              current_test_++;&lt;br /&gt;
+              return tr;&lt;br /&gt;
+          }&lt;br /&gt;
+          else&lt;br /&gt;
+          {&lt;br /&gt;
           return run_test_(current_test_++,obj);&lt;br /&gt;
         }&lt;br /&gt;
+        }&lt;br /&gt;
         catch( const no_such_test&amp;amp; )&lt;br /&gt;
         {&lt;br /&gt;
           continue; &lt;br /&gt;
@@ -774,6 +812,12 @@&lt;br /&gt;
         test_result tr(name_,ti-&amp;gt;first,test_result::fail,ex);&lt;br /&gt;
         return tr;&lt;br /&gt;
       }&lt;br /&gt;
+      catch(const skip_failure&amp;amp; ex)&lt;br /&gt;
+      {&lt;br /&gt;
+        // test failed because of ensure() or similar method&lt;br /&gt;
+        test_result tr(name_,ti-&amp;gt;first,test_result::skip_fail,ex);&lt;br /&gt;
+        return tr;&lt;br /&gt;
+      }&lt;br /&gt;
       catch(const seh&amp;amp; ex)&lt;br /&gt;
       {&lt;br /&gt;
         // test failed with sigsegv, divide by zero, etc&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Save this patch as tut.patch in the same directory as tut.h and apply it from a terminal program like xterm or cygwin with the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ patch -p1 &amp;lt; tut.patch&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TUT-2008-11-30 =&lt;br /&gt;
Internally, TUT has been migrated to the 2008-11-30. This patch will not work against the current code, but is expected to be in use soon.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--- tut.orig/tut_assert.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_assert.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -154,9 +154,23 @@&lt;br /&gt;
     throw failure(msg);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
+/**&lt;br /&gt;
+ * Skip test because of known failure.&lt;br /&gt;
+ */&lt;br /&gt;
+void skip(const char* msg = &amp;quot;&amp;quot;)&lt;br /&gt;
+{&lt;br /&gt;
+    throw skip_failure(msg);&lt;br /&gt;
+}&lt;br /&gt;
+&lt;br /&gt;
+void skip(const std::string&amp;amp; msg)&lt;br /&gt;
+{&lt;br /&gt;
+    throw skip_failure(msg);&lt;br /&gt;
+}&lt;br /&gt;
+&lt;br /&gt;
 } // end of namespace&lt;br /&gt;
 &lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
+&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
diff -u tut.orig/tut_exception.hpp tut.new/tut_exception.hpp&lt;br /&gt;
--- tut.orig/tut_exception.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_exception.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -201,6 +201,26 @@&lt;br /&gt;
     const test_result tr;&lt;br /&gt;
 };&lt;br /&gt;
 &lt;br /&gt;
+/**&lt;br /&gt;
+ * Exception to be throwed when skip_fail() is called.&lt;br /&gt;
+ */&lt;br /&gt;
+struct skip_failure : public failure&lt;br /&gt;
+{&lt;br /&gt;
+    skip_failure(const std::string&amp;amp; msg) &lt;br /&gt;
+        : failure(msg) &lt;br /&gt;
+    {&lt;br /&gt;
+    }&lt;br /&gt;
+&lt;br /&gt;
+    test_result::result_type result() const&lt;br /&gt;
+    {&lt;br /&gt;
+        return test_result::skip;&lt;br /&gt;
+    }&lt;br /&gt;
+&lt;br /&gt;
+    ~skip_failure() throw()&lt;br /&gt;
+    {&lt;br /&gt;
+    }&lt;br /&gt;
+};&lt;br /&gt;
+&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
diff -u tut.orig/tut_result.hpp tut.new/tut_result.hpp&lt;br /&gt;
--- tut.orig/tut_result.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_result.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -51,6 +51,7 @@&lt;br /&gt;
      * ex - test throwed an exceptions&lt;br /&gt;
      * warn - test finished successfully, but test destructor throwed&lt;br /&gt;
      * term - test forced test application to terminate abnormally&lt;br /&gt;
+     * skip - test skpped because it is a known failure case&lt;br /&gt;
      */&lt;br /&gt;
     enum result_type&lt;br /&gt;
     {&lt;br /&gt;
@@ -60,7 +61,8 @@&lt;br /&gt;
         warn,&lt;br /&gt;
         term,&lt;br /&gt;
         ex_ctor,&lt;br /&gt;
-        rethrown&lt;br /&gt;
+        rethrown,&lt;br /&gt;
+        skip,&lt;br /&gt;
     };&lt;br /&gt;
 &lt;br /&gt;
     result_type result;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Save this patch as &amp;lt;code&amp;gt;tut.patch&amp;lt;/code&amp;gt; in the &amp;lt;code&amp;gt;tut-2008-11-30/tut&amp;lt;/code&amp;gt; directory - alongside the &amp;lt;code&amp;gt;tut_assert.hpp&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;tut_exception.hpp&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;tut_result.hpp&amp;lt;/code&amp;gt; files - and apply it from a terminal program like xterm or cygwin with the command: &lt;br /&gt;
&lt;br /&gt;
$ patch -p1 &amp;lt; tut.patch&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Eventlet&amp;diff=321082</id>
		<title>Eventlet</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Eventlet&amp;diff=321082"/>
		<updated>2009-04-16T17:00:48Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* Releases */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Eventlet =&lt;br /&gt;
&lt;br /&gt;
Eventlet is a networking library written in Python. It achieves high scalability by using [http://en.wikipedia.org/wiki/Non-blocking_IO#Select.28.2Fpoll.29_loop non-blocking io] while at the same time retaining high programmer usability by using [http://en.wikipedia.org/wiki/Coroutine coroutines] to make the non-blocking io operations appear blocking at the source code level.&lt;br /&gt;
&lt;br /&gt;
* Example code: [[Eventlet/Examples]]&lt;br /&gt;
* PyPI entry: http://pypi.python.org/pypi/eventlet/&lt;br /&gt;
* Subversion repository: http://svn.secondlife.com/svn/eventlet&lt;br /&gt;
* Mercurial (hg) repository: http://www.donovanpreston.com:8888/eventlet&lt;br /&gt;
* Trac page: http://svn.secondlife.com/trac/eventlet&lt;br /&gt;
* Mailing list: https://lists.secondlife.com/cgi-bin/mailman/listinfo/eventletdev&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
&lt;br /&gt;
[[Eventlet/Documentation]]&lt;br /&gt;
&lt;br /&gt;
== Releases ==&lt;br /&gt;
&lt;br /&gt;
{| cellpadding=&amp;quot;6&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Name&#039;&#039;&#039; || &#039;&#039;&#039;Date&#039;&#039;&#039; || &#039;&#039;&#039;URL&#039;&#039;&#039; &lt;br /&gt;
|-&lt;br /&gt;
| 0.8 || 2008-10-13  || http://pypi.python.org/pypi/eventlet/0.8/&lt;br /&gt;
|-&lt;br /&gt;
| 0.7 || July 29, 2008 || http://pypi.python.org/pypi/eventlet/0.7&lt;br /&gt;
|-&lt;br /&gt;
| 0.6.1 || July 7, 2008 || http://pypi.python.org/pypi/eventlet/0.6.1&lt;br /&gt;
|-&lt;br /&gt;
| beta-1 || Aug 24, 2007 || [http://svn.secondlife.com/trac/eventlet/changeset/8/branches/beta-1?old_path=%2F&amp;amp;format=zip]  [http://svn.secondlife.com/svn/eventlet/branches/beta-1]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
Eventlet runs on Python version 2.3 or greater, with the following dependencies:&lt;br /&gt;
* [http://cheeseshop.python.org/pypi/greenlet greenlet]&lt;br /&gt;
* [http://pyopenssl.sourceforge.net/ pyOpenSSL] if you want to use ssl sockets&lt;br /&gt;
* (if running python versions &amp;lt; 2.4) a deque object in a &amp;lt;code&amp;gt;collections&amp;lt;/code&amp;gt; module.  One option is to copy [http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/259179 this deque] into a file called &amp;lt;code&amp;gt;collections.py&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Eventlet at Linden ==&lt;br /&gt;
&lt;br /&gt;
eventlet is the networking library used to implement the [[backbone]] architecture.  Backbone is primarily an http server, and as such uses the eventlet.httpd module. eventlet itself is responsible only for handling http protocol-level semantics; &amp;quot;web framework&amp;quot; concepts such as URL traversal and html rendering are implemented in a separate python package, [[mulib]].&lt;br /&gt;
&lt;br /&gt;
== Limitations ==&lt;br /&gt;
&lt;br /&gt;
* Not enough test coverage -- the goal is 100%, but we are not there yet.&lt;br /&gt;
* The SSL client does not properly connect to the SSL server, though both client and server interoperate with other SSL implementations (e.g. curl and apache).&lt;br /&gt;
** We could use a) a unit test that reproduces the bug (rather than the hand-testing we have been doing) and b) a fix for said bug.&lt;br /&gt;
* Not tested on Windows&lt;br /&gt;
** There are probably some simple Unix dependencies we introduced by accident.  If you&#039;re running Eventlet on Windows and run into errors, let us know.&lt;br /&gt;
** The eventlet.processes module is known to not work on Windows.&lt;br /&gt;
&lt;br /&gt;
== Eventlet History ==&lt;br /&gt;
&lt;br /&gt;
Eventlet began life as Donovan Preston was talking to Bob Ippolito about coroutine-based non-blocking networking frameworks in Python. Most non-blocking frameworks require you to run the &amp;quot;main loop&amp;quot; in order to perform all network operations, but Donovan wondered if a library written using a trampolining style could get away with transparently running the main loop any time i/o was required, stopping the main loop once no more i/o was scheduled. Bob spent a few days during PyCon 2006 writing a proof-of-concept. He named it eventlet, after the coroutine implementation it used, [http://cheeseshop.python.org/pypi/greenlet greenlet]. Donovan began using eventlet as a light-weight network library for his spare-time project [http://soundfarmer.com/Pavel/trunk/ Pavel], and also began writing some unittests.&lt;br /&gt;
&lt;br /&gt;
* http://svn.red-bean.com/bob/eventlet/trunk/&lt;br /&gt;
&lt;br /&gt;
When Donovan started at Linden Lab in May of 2006, he added eventlet as an svn external in the indra/lib/python directory, to be a dependency of the yet-to-be-named [[backbone]] project (at the time, it was named restserv). However, including eventlet as an svn external meant that any time the externally hosted project had hosting issues, Linden developers were not able to perform svn updates. Thus, the eventlet source was imported into the linden source tree at the same location, and became a fork.&lt;br /&gt;
&lt;br /&gt;
Bob Ippolito has ceased working on eventlet and has stated his desire for Linden to take it&#039;s fork forward to the open source world as &amp;quot;the&amp;quot; eventlet.&lt;br /&gt;
&lt;br /&gt;
== License ==&lt;br /&gt;
Eventlet is made available under the terms of the open source MIT license below.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;EVENTLET&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2005-2006, Bob Ippolito&lt;br /&gt;
&lt;br /&gt;
Copyright (c) 2007, Linden Research, Inc.&lt;br /&gt;
&lt;br /&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &amp;quot;Software&amp;quot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:&lt;br /&gt;
	&lt;br /&gt;
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.&lt;br /&gt;
	&lt;br /&gt;
THE SOFTWARE IS PROVIDED &amp;quot;AS IS&amp;quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=QtWebkitWin32BuildInstructions&amp;diff=224783</id>
		<title>QtWebkitWin32BuildInstructions</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=QtWebkitWin32BuildInstructions&amp;diff=224783"/>
		<updated>2009-02-04T23:51:38Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: QtWebkitWin32BuildInstructions moved to Qt Webkit Win32 Build Instructions: Make the page searchable&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Qt Webkit Win32 Build Instructions]]&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Qt_Webkit_Win32_Build_Instructions&amp;diff=224773</id>
		<title>Qt Webkit Win32 Build Instructions</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Qt_Webkit_Win32_Build_Instructions&amp;diff=224773"/>
		<updated>2009-02-04T23:51:38Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: QtWebkitWin32BuildInstructions moved to Qt Webkit Win32 Build Instructions: Make the page searchable&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These are instructions for building the Qt/WebKit library as well as testgl and&lt;br /&gt;
uBrowser demo apps using WebKit.&lt;br /&gt;
&lt;br /&gt;
If you do not have git, you can download and install from:&lt;br /&gt;
 http://code.google.com/p/msysgit/&lt;br /&gt;
&lt;br /&gt;
Select the option (number 2 of 3) to add git to your path, but not all the unix&lt;br /&gt;
tools that ship with it.&lt;br /&gt;
 &lt;br /&gt;
1) Building the open source Qt snapshot with Visual Studio:&lt;br /&gt;
1.1) Set up directories&lt;br /&gt;
* Start/All Programs/Microsoft Visual Studio 2005/Visual Studio Tools/Visual Studio 2005 Command Prompt&lt;br /&gt;
* mkdir C:\Qt&lt;br /&gt;
1.2) Clone a copy of Qt - about 500 MB&lt;br /&gt;
* cd C:\Qt&lt;br /&gt;
* git clone git://labs.trolltech.com/qt-snapshot&lt;br /&gt;
1.3) Configure Qt, takes about 10 minutes:&lt;br /&gt;
* cd qt-snapshot&lt;br /&gt;
* configure -release -no-qt3support -prefix C:\Qt\qt-snapshot&lt;br /&gt;
* When the license agreement appears, if you agree type:&lt;br /&gt;
* y&amp;lt;enter&amp;gt;&lt;br /&gt;
1.4) Build Qt, without demos.  This takes 1-2 hours.&lt;br /&gt;
* nmake sub-src&lt;br /&gt;
&lt;br /&gt;
After building Qt the release and debug libraries will be in C:\Qt\qt-snapshot\lib&lt;br /&gt;
&lt;br /&gt;
1.5) Create the file C:\Qt\qt-snapshot\bin\qt-vars.bat and put the following in it&lt;br /&gt;
&lt;br /&gt;
@echo off&lt;br /&gt;
echo Setting up a Qt environment...&lt;br /&gt;
set QTDIR=C:\Qt\qt-snapshot&lt;br /&gt;
set PATH=C:\Qt\qt-snapshot\bin;%PATH%&lt;br /&gt;
set QMAKESPEC=win32-msvc2005&lt;br /&gt;
call &amp;quot;C:\Program Files\Microsoft Visual Studio 8\Common7\Tools\vsvars32.bat&amp;quot;&lt;br /&gt;
&lt;br /&gt;
1.6) Make a shortcut to qt-vars.bat on your desktop&lt;br /&gt;
Right-click &amp;gt; Properties on the shortcut and set:&lt;br /&gt;
Target: %COMSPEC% /k &amp;quot;C:\Qt\qt-snapshot\bin\qt-vars.bat&amp;quot;&lt;br /&gt;
Start in: C:\Qt\qt-snapshot&lt;br /&gt;
&lt;br /&gt;
Rename the command prompt shortcut to &amp;quot;Qt Snapshot Command Prompt.&lt;br /&gt;
&lt;br /&gt;
You can test it by opening the prompt and typing qmake --version.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2) Acquire llmozlib&lt;br /&gt;
2.1) Run &amp;quot;Qt Snapshot Command Prompt&amp;quot; and go to &amp;quot;C:\&amp;quot;&lt;br /&gt;
* git clone git://code.staikos.net/llmozlib&lt;br /&gt;
* cd C:\llmozlib&lt;br /&gt;
2.2) Checkout the qtwebkit branch &lt;br /&gt;
* git checkout -f -b qtwebkit origin/qtwebkit&lt;br /&gt;
&lt;br /&gt;
3) Build llmozlib.a&lt;br /&gt;
3.1) Launch the Qt command prompt&lt;br /&gt;
* cd C:\llmozlib\llmozlib2&lt;br /&gt;
* qmake&lt;br /&gt;
* nmake&lt;br /&gt;
&lt;br /&gt;
3) Acquire test dependencies&lt;br /&gt;
 a. Glut: http://www.xmission.com/~nate/glut.html  Grab the library and header zip.&lt;br /&gt;
 a1. Extract the contents of the zip to a c:\llmozlib\llmozlib2\tests\GL&lt;br /&gt;
 b. Glui32: http://glui.sourceforge.net/&lt;br /&gt;
 b1. Extract the zip&lt;br /&gt;
 b2. Open glui\src\msvc\glui.vcproj.  Allow Visual Studio to convert the project.&lt;br /&gt;
 b2. Edit src\include\GL\glut.h&lt;br /&gt;
 b3. Move &amp;quot;#include &amp;lt;cstdlib&amp;gt;&amp;quot; to the top of the file, just under #define GLUI_GLUI_H&lt;br /&gt;
     (hence above #include &amp;lt;GL/glut.h&amp;gt;&lt;br /&gt;
 b4. See http://www.lighthouse3d.com/opengl/glut/ for details on this edit&lt;br /&gt;
 b5. Follow the instructions in the readme.txt to compile the library&lt;br /&gt;
     Make sure to build a release library&lt;br /&gt;
 b6. Copy glui.h and from the include into C:\llmozlib\llmozlib2\tests\GL&lt;br /&gt;
 b7. Copy glui32.lib from msvc/lib into C:\llmozlib\llmozlib2\tests\GL&lt;br /&gt;
&lt;br /&gt;
4) Build testgl and run it&lt;br /&gt;
* cd C:\llmozlib\llmozlib2\tests\testgl&lt;br /&gt;
* qmake CONFIG-=debug&lt;br /&gt;
* nmake&lt;br /&gt;
* ..\GL\testgl.exe&lt;br /&gt;
&lt;br /&gt;
5) Build ubrowser and run it&lt;br /&gt;
* cd C:\llmozlib\llmozlib2\tests\ubrowser&lt;br /&gt;
* qmake CONFIG-=debug&lt;br /&gt;
* nmake&lt;br /&gt;
* ..\GL\ubrowser.exe&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
a.To use Visual studio 2005, under qt *commercial* command prompt to get a .vcproj, run&lt;br /&gt;
  qmake -tp vc&lt;br /&gt;
&lt;br /&gt;
b. Make sure all libs and app are built as Multi-threaded Dll or Multi-threaded debug dll.&lt;br /&gt;
 In Visual Studio this is in Properties-&amp;gt;configuration-&amp;gt;c/c++-&amp;gt;code generation-&amp;gt;runtime library&lt;br /&gt;
&lt;br /&gt;
Troubleshooting:&lt;br /&gt;
1) If you see this, you need to reorder the &amp;lt;cstdlib&amp;gt; and &amp;lt;GL/glut.h&amp;gt; includes.&lt;br /&gt;
&lt;br /&gt;
C:\Program Files\Microsoft Visual Studio 8\VC\include\stdlib.h(406) : error C2381: &#039;exit&#039; : redefinition; __declspec(noreturn) differs&lt;br /&gt;
        ../include\GL/glut.h(146) : see declaration of &#039;exit&#039;&lt;br /&gt;
&lt;br /&gt;
2) uBrowser crashes on startup in stdlib (vc8crt.dll or similar)&lt;br /&gt;
&lt;br /&gt;
This happens when you mix debug and release libraries.  Make sure you are using&lt;br /&gt;
all &amp;quot;release&amp;quot; builds of GLUI and ubrowser.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User_talk:Phoenix_Linden&amp;diff=173683</id>
		<title>User talk:Phoenix Linden</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User_talk:Phoenix_Linden&amp;diff=173683"/>
		<updated>2008-12-13T03:25:43Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==[[Tao of Linden]]==&lt;br /&gt;
Heyas!&amp;lt;br&amp;gt;I noticed you Sysop-locked the [[Tao of Linden]] article so I wanted to request if you could add &amp;lt;nowiki&amp;gt;{{Help|Glossary=*}}&amp;lt;/nowiki&amp;gt; on top of the article. It would insert a header like the one in the [[Linden]] article and would register it to certain categories.&amp;lt;br&amp;gt;&lt;br /&gt;
On a sidenote: Are these translations you&#039;re storing at [[User:Phoenix Linden#scratch work]]? Since &#039;&#039;Ich leibe Buchen&#039;&#039; has a typo (leibe -&amp;gt; liebe) and I guess it&#039;s not what you meant. &#039;&#039;Buchen&#039;&#039; [http://de.wikipedia.org/wiki/Buchen are trees] (beeches). &#039;&#039;Bücher&#039;&#039; are books. So should be &amp;quot;&#039;&#039;Ich liebe Bücher&#039;&#039;&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Kewl rezdate btw ^_^&amp;lt;br&amp;gt;&lt;br /&gt;
Greetz, [[Image:Zai_signature.png|45px]] &#039;&#039;&#039;[[User:Zai Lynch|Lynch]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Zai Lynch|talk]]|[[Special:Contributions/Zai Lynch|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 02:45, 13 December 2008 (UTC)&lt;br /&gt;
:P.S.: Maybe you can also add a &#039;&#039;Related Links&#039;&#039; section, linking to [[Tao of Volunteers]], maybe [[Linden]], [[Linden Lab]], the [http://lindenlab.com/about/tao Tao on the official Website], add some [http://blog.secondlife.com/2006/07/25/the-tao-of-linden/ history about the tao]... I think it would be expandable. Sad that it&#039;s locked.&lt;br /&gt;
:[[Image:Zai_signature.png|45px]] &#039;&#039;&#039;[[User:Zai Lynch|Lynch]]&#039;&#039;&#039; &amp;lt;sup&amp;gt;&amp;lt;small&amp;gt;([[User talk:Zai Lynch|talk]]|[[Special:Contributions/Zai Lynch|contribs]])&amp;lt;/small&amp;gt;&amp;lt;/sup&amp;gt; 03:18, 13 December 2008 (UTC)&lt;br /&gt;
:: I lock the page because the text is part of [[Linden]] policy. I don&#039;t know if the [[:Template:Help]] link is that useful in this case because we do not have translations at this time, but I will contemplate adding a related links section to cover things like [[Linden Lab]]. Thanks for the feedback. [[User:Phoenix Linden|Phoenix Linden]] 03:25, 13 December 2008 (UTC)&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Tao_of_Linden&amp;diff=173553</id>
		<title>Tao of Linden</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Tao_of_Linden&amp;diff=173553"/>
		<updated>2008-12-12T23:03:53Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: Changed protection level for &amp;quot;Tao of Linden&amp;quot; [edit=sysop:move=sysop]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Vision and Mission == &lt;br /&gt;
&amp;lt;b&amp;gt;To connect us all to an online world that improves the human condition.&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Company Principles ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Work Together.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We are engaged in a wildly ambitious and complex endeavor.  We need to take on risk and accept the occasional failure. But we dream, stumble and win only together.   This requires a level of creative collaboration you won’t find in many companies. You must not only respect but actively seek out differing views, and then find closure after dissent to move forward together.  When you look back, do so to find ways to improve rather than to blame.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Walk in our Residents’ shoes.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We are blessed by some of the most informed, passionate, committed customers imaginable.  They are our reason for being, they are our world, and we call them Residents.  They are an insuperable source of advantage and an awesome responsibility.  In every choice you make, consider how your choice will impact their experience.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Good People Make Good Choices . . . &#039;&#039;and vice versa&#039;&#039;.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There’s love in the spirit of our mission, the enjoyment we take in each others’ company, the style and humor we have at our best.  We’re here because we’re open to all the wonders of the world and the goodness in each other; even the cynics among us harbor the begrudging belief that all things are possible.  This is a place where you can be you, and we ask you to make the choices that enable your colleagues to bring out the best in themselves.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Be thoughtful and transparent.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
We build trust through transparent and open communication.  Be prolific in your communication but thoughtful, and remember that context is key.  Report on your progress regularly and in language that benefits the widest possible range of your colleagues.  You are responsible for ensuring that your messages reach your intended audience - make sure your signal does not become noise.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;No Politics.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Sharing our mission requires that you honor this rule at all times:   Never act to advance your own interests or someone else’s interests at the expense of the interests of the company.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Tao_of_Linden&amp;diff=173523</id>
		<title>Tao of Linden</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Tao_of_Linden&amp;diff=173523"/>
		<updated>2008-12-12T22:53:04Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: Changed protection level for &amp;quot;Tao of Linden&amp;quot; [edit=autoconfirmed:move=autoconfirmed]&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Vision and Mission == &lt;br /&gt;
&amp;lt;b&amp;gt;To connect us all to an online world that improves the human condition.&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Company Principles ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; Work together! &#039;&#039;&#039;  &lt;br /&gt;
&lt;br /&gt;
The problems we face in creating Second Life are usually larger than one person can solve, and solving them together is one of the great strengths we have as a company.  We will succeed only if we collaborate with each other extensively and well.  This means helping others reach their goals, asking for help and input often, and being easy to work with.  Create teams as necessary to solve specific problems, and support your teammates.  Remember that being open and honest is essential, but is only the threshold requirement - great collaborative work requires intuitive compassion and support. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; Your Choice is Your Responsibility &#039;&#039;&#039;  &lt;br /&gt;
&lt;br /&gt;
There&#039;s a dual meaning here.  &lt;br /&gt;
&lt;br /&gt;
Most companies tell you what to do.  Then they make you accountable to the person who told you what to do, not to yourself.  We don&#039;t think this gets the best long-term results with a truly ambitious project like Second Life.  At Linden Lab, you are expected to choose your own work, you have to decide how you can best move the company forward.  This isn&#039;t always easy, but it can be very rewarding for you and it is a huge win for the company.  &#039;&#039;This doesn&#039;t mean that you can&#039;t ask someone else what to do&#039;&#039; - it means that you are responsible for choosing who to listen to!  You are responsible for listening well and broadly enough to choose wisely.&lt;br /&gt;
&lt;br /&gt;
And once you have chosen, you are responsible for executing well to making your choices work.  You must understand that other people now rely on you for single-minded execution, and it is time to shut out the noise and work without distraction.  Sometimes you will fail, and in those cases it is very important to fail fast and fail publicly - that is how we learn and iterate and ultimately win.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; Be Transparent and Open &#039;&#039;&#039;  &lt;br /&gt;
&lt;br /&gt;
There are many ways to emphasize responsibility, accountability, communication and trust.  We believe that the one key principle that best supports all of these values is transparency.  As much as possible, tell everyone what you are doing, all the time.  This transparency makes us responsible to our peers, makes us accountable to our own statements, and replaces the need for management with individual responsibility.  Over time, it creates and reinforces trust.  Be willing to share ideas before you feel they are ‘baked’.  Report on your own progress frequently and to everyone. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; Make Weekly Progress &#039;&#039;&#039;  &lt;br /&gt;
&lt;br /&gt;
We believe that every person should make specific, visible individual contributions that moves the company forward every week.  Projects must be broken down into measurable tasks so that making weekly progress is possible.  This is a principle that almost no one believes is true when they first hear it,  yet everyone who keeps to this principle over the course of several months is stunned by the amount of progress made during that time.  Set weekly goals and report progress to everyone.  Regardless how big what you are working on may be, you can always break it down this way.  Give it a try.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; No Politics! &#039;&#039;&#039;  &lt;br /&gt;
&lt;br /&gt;
Never act to advance your own interests or someone else&#039;s interests at the expense of the interests of the company.  This is the one principle, outside of violations of law, for which violation will likely result in immediate termination. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; Might Makes Right &#039;&#039;&#039;  &lt;br /&gt;
&lt;br /&gt;
Just kidding – wanted to make sure you’re still paying attention.  Lots of things could be said here: Have a sense of humor.  Have a sense of humility.  Have fun.  Call out inconsistency in principles when you see it.  Don’t let a staid form and function become routine and boilerplate.  Which leads to our last principle . . .&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039; Do It With Style &#039;&#039;&#039;  &lt;br /&gt;
&lt;br /&gt;
It’s not enough that we are changing the world.  It’s not enough that Second Life is incredibly complex and our vision is vast and shifting.  We’re not just going to succeed, we’re going to do it with style.  As with life, the journey matters as much as the destination.  That means a lot of different things, and a lot of what it means can’t be captured in words alone.  Find out by talking to your colleagues, by living the principles above, and by exploring Second Life.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Patch_TUT&amp;diff=168963</id>
		<title>Patch TUT</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Patch_TUT&amp;diff=168963"/>
		<updated>2008-12-09T18:45:07Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* TUT-2008-11-30 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Our unit test framework did not have any method for skipping tests. Sometimes known failure cases are found which require temporarily skipping tests. This patch adds that functionality.&lt;br /&gt;
&lt;br /&gt;
= TUT-2006-11-04 =&lt;br /&gt;
&#039;&#039;&#039;WARNING&#039;&#039;&#039;: This is a patch to a pretty old version of tut, but currently the version in use.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--- tut-orig/tut.h	2007-05-23 16:37:00.000000000 -0700&lt;br /&gt;
+++ tut-new/tut.h	2007-05-23 16:40:18.000000000 -0700&lt;br /&gt;
@@ -79,6 +79,15 @@&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
   /**&lt;br /&gt;
+   * Exception to be throwed when skip_fail() is called.&lt;br /&gt;
+   */&lt;br /&gt;
+  class skip_failure : public std::logic_error&lt;br /&gt;
+  {&lt;br /&gt;
+    public:&lt;br /&gt;
+      skip_failure(const std::string&amp;amp; msg) : std::logic_error(msg){};&lt;br /&gt;
+  };&lt;br /&gt;
+&lt;br /&gt;
+  /**&lt;br /&gt;
    * Exception to be throwed when test desctructor throwed an exception.&lt;br /&gt;
    */&lt;br /&gt;
   class warning : public std::logic_error&lt;br /&gt;
@@ -120,8 +129,20 @@&lt;br /&gt;
      * ex - test throwed an exceptions&lt;br /&gt;
      * warn - test finished successfully, but test destructor throwed&lt;br /&gt;
      * term - test forced test application to terminate abnormally&lt;br /&gt;
+     * skip - test skipped&lt;br /&gt;
+     * skip_fail - test skpped because it is a known failure case&lt;br /&gt;
      */&lt;br /&gt;
-    typedef enum { ok, fail, ex, warn, term, ex_ctor } result_type;&lt;br /&gt;
+    typedef enum&lt;br /&gt;
+	{&lt;br /&gt;
+		ok,&lt;br /&gt;
+		fail,&lt;br /&gt;
+		ex,&lt;br /&gt;
+		warn,&lt;br /&gt;
+		term,&lt;br /&gt;
+		ex_ctor,&lt;br /&gt;
+		skip,&lt;br /&gt;
+		skip_fail,&lt;br /&gt;
+	} result_type;&lt;br /&gt;
     result_type result;&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
@@ -168,7 +189,7 @@&lt;br /&gt;
&lt;br /&gt;
     // execute tests iteratively&lt;br /&gt;
     virtual void rewind() = 0;&lt;br /&gt;
-    virtual test_result run_next() = 0;&lt;br /&gt;
+    virtual test_result run_next(int skip_test_id = 0) = 0;&lt;br /&gt;
&lt;br /&gt;
     // execute one test&lt;br /&gt;
     virtual test_result run_test(int n) = 0;&lt;br /&gt;
@@ -316,7 +337,7 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Runs all tests in specified group.&lt;br /&gt;
      */&lt;br /&gt;
-    void run_tests(const std::string&amp;amp; group_name) const&lt;br /&gt;
+    void run_tests(const std::string&amp;amp; group_name, int skip_test_id = 0) const&lt;br /&gt;
     {&lt;br /&gt;
       callback_-&amp;gt;run_started();&lt;br /&gt;
&lt;br /&gt;
@@ -328,7 +349,7 @@&lt;br /&gt;
&lt;br /&gt;
       try&lt;br /&gt;
       {&lt;br /&gt;
-        run_all_tests_in_group_(i);&lt;br /&gt;
+        run_all_tests_in_group_(i, skip_test_id);&lt;br /&gt;
       }&lt;br /&gt;
       catch( const no_more_tests&amp;amp; )&lt;br /&gt;
       {&lt;br /&gt;
@@ -371,12 +392,13 @@&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     private:&lt;br /&gt;
-    void run_all_tests_in_group_(const_iterator i) const&lt;br /&gt;
+    void run_all_tests_in_group_(const_iterator i, int skip_test_id = 0) const&lt;br /&gt;
     {&lt;br /&gt;
       i-&amp;gt;second-&amp;gt;rewind();&lt;br /&gt;
       for( ;; )&lt;br /&gt;
       {&lt;br /&gt;
-        test_result tr = i-&amp;gt;second-&amp;gt;run_next();&lt;br /&gt;
+        test_result tr = i-&amp;gt;second-&amp;gt;run_next(skip_test_id);&lt;br /&gt;
+&lt;br /&gt;
         callback_-&amp;gt;test_completed(tr);&lt;br /&gt;
&lt;br /&gt;
 	if( tr.result == test_result::ex_ctor )&lt;br /&gt;
@@ -436,13 +458,11 @@&lt;br /&gt;
     }&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
-  namespace &lt;br /&gt;
-  {&lt;br /&gt;
     /**&lt;br /&gt;
      * Tests provided condition.&lt;br /&gt;
      * Throws if false.&lt;br /&gt;
      */&lt;br /&gt;
-    void ensure(bool cond)&lt;br /&gt;
+    inline void ensure(bool cond)&lt;br /&gt;
     {&lt;br /&gt;
        if( !cond ) throw failure(&amp;quot;&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
@@ -511,10 +531,19 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Unconditionally fails with message.&lt;br /&gt;
      */&lt;br /&gt;
-    void fail(const char* msg=&amp;quot;&amp;quot;)&lt;br /&gt;
+	template &amp;lt;class T&amp;gt;&lt;br /&gt;
+    void fail(const T msg)&lt;br /&gt;
     {&lt;br /&gt;
       throw failure(msg);&lt;br /&gt;
     }&lt;br /&gt;
+&lt;br /&gt;
+    /**&lt;br /&gt;
+     * Unconditionally fails with message.&lt;br /&gt;
+     */&lt;br /&gt;
+	template &amp;lt;class T&amp;gt;&lt;br /&gt;
+    void skip_fail(const T msg)&lt;br /&gt;
+    {&lt;br /&gt;
+      throw skip_failure(msg);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   /**&lt;br /&gt;
@@ -705,7 +734,7 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Runs next test.&lt;br /&gt;
      */&lt;br /&gt;
-    test_result run_next()&lt;br /&gt;
+    test_result run_next(int skip_test_id = 0)&lt;br /&gt;
     {&lt;br /&gt;
       if( current_test_ == tests_.end() )&lt;br /&gt;
       {&lt;br /&gt;
@@ -718,8 +747,17 @@&lt;br /&gt;
       {&lt;br /&gt;
         try&lt;br /&gt;
         {&lt;br /&gt;
+          if (current_test_-&amp;gt;first == skip_test_id)&lt;br /&gt;
+          {&lt;br /&gt;
+              test_result tr(name_,current_test_-&amp;gt;first,test_result::skip);&lt;br /&gt;
+              current_test_++;&lt;br /&gt;
+              return tr;&lt;br /&gt;
+          }&lt;br /&gt;
+          else&lt;br /&gt;
+          {&lt;br /&gt;
           return run_test_(current_test_++,obj);&lt;br /&gt;
         }&lt;br /&gt;
+        }&lt;br /&gt;
         catch( const no_such_test&amp;amp; )&lt;br /&gt;
         {&lt;br /&gt;
           continue; &lt;br /&gt;
@@ -774,6 +812,12 @@&lt;br /&gt;
         test_result tr(name_,ti-&amp;gt;first,test_result::fail,ex);&lt;br /&gt;
         return tr;&lt;br /&gt;
       }&lt;br /&gt;
+      catch(const skip_failure&amp;amp; ex)&lt;br /&gt;
+      {&lt;br /&gt;
+        // test failed because of ensure() or similar method&lt;br /&gt;
+        test_result tr(name_,ti-&amp;gt;first,test_result::skip_fail,ex);&lt;br /&gt;
+        return tr;&lt;br /&gt;
+      }&lt;br /&gt;
       catch(const seh&amp;amp; ex)&lt;br /&gt;
       {&lt;br /&gt;
         // test failed with sigsegv, divide by zero, etc&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Save this patch as tut.patch in the same directory as tut.h and apply it from a terminal program like xterm or cygwin with the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ patch -p1 &amp;lt; tut.patch&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TUT-2008-11-30 =&lt;br /&gt;
Internally, TUT has been migrated to the 2008-11-30. This patch will not work against the current code, but is expected to be in use soon.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--- tut.orig/tut_assert.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_assert.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -154,9 +154,23 @@&lt;br /&gt;
    throw failure(msg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
+/**&lt;br /&gt;
+ * Skip test because of known failure.&lt;br /&gt;
+ */&lt;br /&gt;
+void skip(const char* msg = &amp;quot;&amp;quot;)&lt;br /&gt;
+{&lt;br /&gt;
+    throw skip_failure(msg);&lt;br /&gt;
+}&lt;br /&gt;
+&lt;br /&gt;
+void skip(const std::string&amp;amp; msg)&lt;br /&gt;
+{&lt;br /&gt;
+    throw skip_failure(msg);&lt;br /&gt;
+}&lt;br /&gt;
+&lt;br /&gt;
} // end of namespace&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
+&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
diff -u tut.orig/tut_exception.hpp tut.new/tut_exception.hpp&lt;br /&gt;
--- tut.orig/tut_exception.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_exception.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -201,6 +201,26 @@&lt;br /&gt;
    const test_result tr;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
+/**&lt;br /&gt;
+ * Exception to be throwed when skip_fail() is called.&lt;br /&gt;
+ */&lt;br /&gt;
+struct skip_failure : public failure&lt;br /&gt;
+{&lt;br /&gt;
+    skip_failure(const std::string&amp;amp; msg) &lt;br /&gt;
+        : failure(msg) &lt;br /&gt;
+    {&lt;br /&gt;
+    }&lt;br /&gt;
+&lt;br /&gt;
+    test_result::result_type result() const&lt;br /&gt;
+    {&lt;br /&gt;
+        return test_result::skip;&lt;br /&gt;
+    }&lt;br /&gt;
+&lt;br /&gt;
+    ~skip_failure() throw()&lt;br /&gt;
+    {&lt;br /&gt;
+    }&lt;br /&gt;
+};&lt;br /&gt;
+&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
diff -u tut.orig/tut_result.hpp tut.new/tut_result.hpp&lt;br /&gt;
--- tut.orig/tut_result.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_result.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -51,6 +51,7 @@&lt;br /&gt;
     * ex - test throwed an exceptions&lt;br /&gt;
     * warn - test finished successfully, but test destructor throwed&lt;br /&gt;
     * term - test forced test application to terminate abnormally&lt;br /&gt;
+     * skip - test skpped because it is a known failure case&lt;br /&gt;
     */&lt;br /&gt;
    enum result_type&lt;br /&gt;
    {&lt;br /&gt;
@@ -60,7 +61,8 @@&lt;br /&gt;
        warn,&lt;br /&gt;
        term,&lt;br /&gt;
        ex_ctor,&lt;br /&gt;
-        rethrown&lt;br /&gt;
+        rethrown,&lt;br /&gt;
+        skip,&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    result_type result;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Patch_TUT&amp;diff=167673</id>
		<title>Patch TUT</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Patch_TUT&amp;diff=167673"/>
		<updated>2008-12-08T18:38:20Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Our unit test framework did not have any method for skipping tests. Sometimes known failure cases are found which require temporarily skipping tests. This patch adds that functionality.&lt;br /&gt;
&lt;br /&gt;
= TUT-2006-11-04 =&lt;br /&gt;
&#039;&#039;&#039;WARNING&#039;&#039;&#039;: This is a patch to a pretty old version of tut, but currently the version in use.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--- tut-orig/tut.h	2007-05-23 16:37:00.000000000 -0700&lt;br /&gt;
+++ tut-new/tut.h	2007-05-23 16:40:18.000000000 -0700&lt;br /&gt;
@@ -79,6 +79,15 @@&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
   /**&lt;br /&gt;
+   * Exception to be throwed when skip_fail() is called.&lt;br /&gt;
+   */&lt;br /&gt;
+  class skip_failure : public std::logic_error&lt;br /&gt;
+  {&lt;br /&gt;
+    public:&lt;br /&gt;
+      skip_failure(const std::string&amp;amp; msg) : std::logic_error(msg){};&lt;br /&gt;
+  };&lt;br /&gt;
+&lt;br /&gt;
+  /**&lt;br /&gt;
    * Exception to be throwed when test desctructor throwed an exception.&lt;br /&gt;
    */&lt;br /&gt;
   class warning : public std::logic_error&lt;br /&gt;
@@ -120,8 +129,20 @@&lt;br /&gt;
      * ex - test throwed an exceptions&lt;br /&gt;
      * warn - test finished successfully, but test destructor throwed&lt;br /&gt;
      * term - test forced test application to terminate abnormally&lt;br /&gt;
+     * skip - test skipped&lt;br /&gt;
+     * skip_fail - test skpped because it is a known failure case&lt;br /&gt;
      */&lt;br /&gt;
-    typedef enum { ok, fail, ex, warn, term, ex_ctor } result_type;&lt;br /&gt;
+    typedef enum&lt;br /&gt;
+	{&lt;br /&gt;
+		ok,&lt;br /&gt;
+		fail,&lt;br /&gt;
+		ex,&lt;br /&gt;
+		warn,&lt;br /&gt;
+		term,&lt;br /&gt;
+		ex_ctor,&lt;br /&gt;
+		skip,&lt;br /&gt;
+		skip_fail,&lt;br /&gt;
+	} result_type;&lt;br /&gt;
     result_type result;&lt;br /&gt;
&lt;br /&gt;
     /**&lt;br /&gt;
@@ -168,7 +189,7 @@&lt;br /&gt;
&lt;br /&gt;
     // execute tests iteratively&lt;br /&gt;
     virtual void rewind() = 0;&lt;br /&gt;
-    virtual test_result run_next() = 0;&lt;br /&gt;
+    virtual test_result run_next(int skip_test_id = 0) = 0;&lt;br /&gt;
&lt;br /&gt;
     // execute one test&lt;br /&gt;
     virtual test_result run_test(int n) = 0;&lt;br /&gt;
@@ -316,7 +337,7 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Runs all tests in specified group.&lt;br /&gt;
      */&lt;br /&gt;
-    void run_tests(const std::string&amp;amp; group_name) const&lt;br /&gt;
+    void run_tests(const std::string&amp;amp; group_name, int skip_test_id = 0) const&lt;br /&gt;
     {&lt;br /&gt;
       callback_-&amp;gt;run_started();&lt;br /&gt;
&lt;br /&gt;
@@ -328,7 +349,7 @@&lt;br /&gt;
&lt;br /&gt;
       try&lt;br /&gt;
       {&lt;br /&gt;
-        run_all_tests_in_group_(i);&lt;br /&gt;
+        run_all_tests_in_group_(i, skip_test_id);&lt;br /&gt;
       }&lt;br /&gt;
       catch( const no_more_tests&amp;amp; )&lt;br /&gt;
       {&lt;br /&gt;
@@ -371,12 +392,13 @@&lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     private:&lt;br /&gt;
-    void run_all_tests_in_group_(const_iterator i) const&lt;br /&gt;
+    void run_all_tests_in_group_(const_iterator i, int skip_test_id = 0) const&lt;br /&gt;
     {&lt;br /&gt;
       i-&amp;gt;second-&amp;gt;rewind();&lt;br /&gt;
       for( ;; )&lt;br /&gt;
       {&lt;br /&gt;
-        test_result tr = i-&amp;gt;second-&amp;gt;run_next();&lt;br /&gt;
+        test_result tr = i-&amp;gt;second-&amp;gt;run_next(skip_test_id);&lt;br /&gt;
+&lt;br /&gt;
         callback_-&amp;gt;test_completed(tr);&lt;br /&gt;
&lt;br /&gt;
 	if( tr.result == test_result::ex_ctor )&lt;br /&gt;
@@ -436,13 +458,11 @@&lt;br /&gt;
     }&lt;br /&gt;
   };&lt;br /&gt;
&lt;br /&gt;
-  namespace &lt;br /&gt;
-  {&lt;br /&gt;
     /**&lt;br /&gt;
      * Tests provided condition.&lt;br /&gt;
      * Throws if false.&lt;br /&gt;
      */&lt;br /&gt;
-    void ensure(bool cond)&lt;br /&gt;
+    inline void ensure(bool cond)&lt;br /&gt;
     {&lt;br /&gt;
        if( !cond ) throw failure(&amp;quot;&amp;quot;);&lt;br /&gt;
     }&lt;br /&gt;
@@ -511,10 +531,19 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Unconditionally fails with message.&lt;br /&gt;
      */&lt;br /&gt;
-    void fail(const char* msg=&amp;quot;&amp;quot;)&lt;br /&gt;
+	template &amp;lt;class T&amp;gt;&lt;br /&gt;
+    void fail(const T msg)&lt;br /&gt;
     {&lt;br /&gt;
       throw failure(msg);&lt;br /&gt;
     }&lt;br /&gt;
+&lt;br /&gt;
+    /**&lt;br /&gt;
+     * Unconditionally fails with message.&lt;br /&gt;
+     */&lt;br /&gt;
+	template &amp;lt;class T&amp;gt;&lt;br /&gt;
+    void skip_fail(const T msg)&lt;br /&gt;
+    {&lt;br /&gt;
+      throw skip_failure(msg);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   /**&lt;br /&gt;
@@ -705,7 +734,7 @@&lt;br /&gt;
     /**&lt;br /&gt;
      * Runs next test.&lt;br /&gt;
      */&lt;br /&gt;
-    test_result run_next()&lt;br /&gt;
+    test_result run_next(int skip_test_id = 0)&lt;br /&gt;
     {&lt;br /&gt;
       if( current_test_ == tests_.end() )&lt;br /&gt;
       {&lt;br /&gt;
@@ -718,8 +747,17 @@&lt;br /&gt;
       {&lt;br /&gt;
         try&lt;br /&gt;
         {&lt;br /&gt;
+          if (current_test_-&amp;gt;first == skip_test_id)&lt;br /&gt;
+          {&lt;br /&gt;
+              test_result tr(name_,current_test_-&amp;gt;first,test_result::skip);&lt;br /&gt;
+              current_test_++;&lt;br /&gt;
+              return tr;&lt;br /&gt;
+          }&lt;br /&gt;
+          else&lt;br /&gt;
+          {&lt;br /&gt;
           return run_test_(current_test_++,obj);&lt;br /&gt;
         }&lt;br /&gt;
+        }&lt;br /&gt;
         catch( const no_such_test&amp;amp; )&lt;br /&gt;
         {&lt;br /&gt;
           continue; &lt;br /&gt;
@@ -774,6 +812,12 @@&lt;br /&gt;
         test_result tr(name_,ti-&amp;gt;first,test_result::fail,ex);&lt;br /&gt;
         return tr;&lt;br /&gt;
       }&lt;br /&gt;
+      catch(const skip_failure&amp;amp; ex)&lt;br /&gt;
+      {&lt;br /&gt;
+        // test failed because of ensure() or similar method&lt;br /&gt;
+        test_result tr(name_,ti-&amp;gt;first,test_result::skip_fail,ex);&lt;br /&gt;
+        return tr;&lt;br /&gt;
+      }&lt;br /&gt;
       catch(const seh&amp;amp; ex)&lt;br /&gt;
       {&lt;br /&gt;
         // test failed with sigsegv, divide by zero, etc&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Save this patch as tut.patch in the same directory as tut.h and apply it from a terminal program like xterm or cygwin with the command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ patch -p1 &amp;lt; tut.patch&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= TUT-2008-11-30 =&lt;br /&gt;
Internally, TUT has been migrated to the 2008-11-30. This patch will not work against the current code, but is expected to be in use soon.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--- tut.orig/tut_assert.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_assert.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -154,9 +154,23 @@&lt;br /&gt;
    throw failure(msg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
+/**&lt;br /&gt;
+ * Skip test because of known failure.&lt;br /&gt;
+ */&lt;br /&gt;
+void skip(const char* msg = &amp;quot;&amp;quot;)&lt;br /&gt;
+{&lt;br /&gt;
+    throw skip_failure(msg);&lt;br /&gt;
+}&lt;br /&gt;
+&lt;br /&gt;
+void skip(const std::string&amp;amp; msg)&lt;br /&gt;
+{&lt;br /&gt;
+    throw skip_failure(msg);&lt;br /&gt;
+}&lt;br /&gt;
+&lt;br /&gt;
} // end of namespace&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
+&lt;br /&gt;
#endif&lt;br /&gt;
&lt;br /&gt;
diff -u tut.orig/tut_exception.hpp tut.new/tut_exception.hpp&lt;br /&gt;
--- tut.orig/tut_exception.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_exception.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -201,6 +201,26 @@&lt;br /&gt;
    const test_result tr;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
+/**&lt;br /&gt;
+ * Exception to be throwed when skip_fail() is called.&lt;br /&gt;
+ */&lt;br /&gt;
+struct skip_failure : public failure&lt;br /&gt;
+{&lt;br /&gt;
+    skip_failure(const std::string&amp;amp; msg) &lt;br /&gt;
+        : failure(msg) &lt;br /&gt;
+    {&lt;br /&gt;
+    }&lt;br /&gt;
+&lt;br /&gt;
+    test_result::result_type result() const&lt;br /&gt;
+    {&lt;br /&gt;
+        return test_result::skip;&lt;br /&gt;
+    }&lt;br /&gt;
+&lt;br /&gt;
+    ~skip_failure() throw()&lt;br /&gt;
+    {&lt;br /&gt;
+    }&lt;br /&gt;
+};&lt;br /&gt;
+&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#endif&lt;br /&gt;
diff -u tut.orig/tut_result.hpp tut.new/tut_result.hpp&lt;br /&gt;
--- tut.orig/tut_result.hpp	2008-12-05 17:35:10.000000000 -0800&lt;br /&gt;
+++ tut.new/tut_result.hpp	2008-12-05 17:37:56.000000000 -0800&lt;br /&gt;
@@ -51,6 +51,7 @@&lt;br /&gt;
     * ex - test throwed an exceptions&lt;br /&gt;
     * warn - test finished successfully, but test destructor throwed&lt;br /&gt;
     * term - test forced test application to terminate abnormally&lt;br /&gt;
+     * skip - test skpped because it is a known failure case&lt;br /&gt;
     */&lt;br /&gt;
    enum result_type&lt;br /&gt;
    {&lt;br /&gt;
@@ -60,7 +61,8 @@&lt;br /&gt;
        warn,&lt;br /&gt;
        term,&lt;br /&gt;
        ex_ctor,&lt;br /&gt;
-        rethrown&lt;br /&gt;
+        rethrown,&lt;br /&gt;
+        skip,&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    result_type result;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Internally,&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Bug_Tracker&amp;diff=61368</id>
		<title>Bug Tracker</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Bug_Tracker&amp;diff=61368"/>
		<updated>2008-04-04T20:21:33Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* Security Issues -- a.k.a &amp;quot;the missing Fifth Project&amp;quot; */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Multi-lang}}&lt;br /&gt;
&lt;br /&gt;
{{OSWikiContribBox|parent=QA}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: red; font-weight: bold;&amp;quot;&amp;gt;The JIRA Issue Tracker is &#039;&#039;not&#039;&#039; for technical support-type requests.&amp;lt;/span&amp;gt;  &#039;&#039;&#039;If you&#039;re looking for account-specific help, please use our [http://secondlife.com/support support resources].&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE&#039;&#039;&#039;: All submissions to this site (JIRA included) are governed by the [[Project:Contribution_Agreement|Second Life Project Contribution Agreement]].  By submitting patches and other information using this site, you acknowledge that you&#039;ve read, understood, and agreed to those terms.&lt;br /&gt;
&lt;br /&gt;
= What is the Issue Tracker or PJIRA? =&lt;br /&gt;
[[Image:JIRA.jpg|thumb]]The public issue tracker, known as &amp;quot;Public JIRA&amp;quot;, &amp;quot;PJIRA&amp;quot;, or just &amp;quot;JIRA&amp;quot;, is an issue-tracking project management tool made by [http://www.atlassian.com/software/jira Atlassian] that is located at http://jira.secondlife.com.  It&#039;s used by the Second Life open source initiative to organize issues (i.e. bugs and feature requests) submitted by the Second Life community into a searchable database.  You, too, can submit issues you find when using the open source or standard versions of Second Life.  Please familiarize yourself with the information in this page before proceeding to JIRA.&lt;br /&gt;
&lt;br /&gt;
= How it works =&lt;br /&gt;
Bug reports created in JIRA are composed of a description of the problem and, if possible, a reproduction.  New features are composed of descriptions of the proposed feature and how it should work.  Both types of issues then get contributions from other users, such as better or simpler descriptions and reproductions, and popular issues accumulate votes from other users.  Programmers in the open source community can attach &amp;quot;patches&amp;quot;, changes to the code that fix or implement the issue.  These votes, as well as events like [[bug triage]]s, help prioritize the issues.  Those which are acknowledged are &amp;quot;imported&amp;quot; into the Lindens&#039; private copy of JIRA.&lt;br /&gt;
&lt;br /&gt;
After the issue gets Linden attention, others can still continue to help.:&lt;br /&gt;
&lt;br /&gt;
* Once the changes are completed and awaiting release to the public, the bug is resolved as &#039;&#039;&#039;&amp;quot;Fix Pending&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
* When the change has been made available, it&#039;s resolved as &#039;&#039;&#039;&amp;quot;Fixed&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
* Generally, after being confirmed by Linden Lab&#039;s Quality Assurance Team and our community, its status is changed from &amp;quot;Resolved&amp;quot; to &#039;&#039;&#039;&amp;quot;Closed&amp;quot;&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
In addition to &amp;quot;Fix Pending&amp;quot; and &amp;quot;Fixed&amp;quot;, an issue can also be resolved or closed if it appears to be a duplicate of another issue, unreproducible, misfiled, not a bug, incomplete, etc.&lt;br /&gt;
&lt;br /&gt;
= Second Life JIRA FAQ =&lt;br /&gt;
&lt;br /&gt;
== Caveats ==&lt;br /&gt;
&amp;lt;span style=&amp;quot;color: red; font-weight: bold;&amp;quot;&amp;gt;The JIRA Issue Tracker is &#039;&#039;not&#039;&#039; for technical support&amp;lt;/span&amp;gt;, so please do &#039;&#039;&#039;&#039;&#039;not&#039;&#039;&#039;&#039;&#039; enter issues like:&lt;br /&gt;
&lt;br /&gt;
:* &amp;quot;I keep crashing and want it to stop now!&amp;quot;&lt;br /&gt;
:* &amp;quot;Someone stole my L$&amp;quot;&lt;br /&gt;
:* &amp;quot;The sim I&#039;m in is LAGGIN BAD&amp;quot;&lt;br /&gt;
:* &amp;quot;How do I build a house?&amp;quot;&lt;br /&gt;
:* [https://jira.secondlife.com/secure/QuickSearch.jspa?searchString=misfiled More examples of misfiled issues]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Entering misfiled issues which &#039;&#039;aren&#039;t&#039;&#039; actionable and &#039;&#039;don&#039;t&#039;&#039; contain clear instructions (see below for more info) makes it harder for your fellow Residents to use the Issue Tracker.&#039;&#039;&#039; If you&#039;re looking for personal assistance, please send your message to the right place by [http://secondlife.com/community/support.php contacting Support] (towards the bottom of the page), and be sure to include &#039;&#039;useful details&#039;&#039; to help us help you.&lt;br /&gt;
&lt;br /&gt;
Before reporting issues, we recommend you thoroughly search the [http://secondlife.com/community/support.php support resources] first and look for the latest news and status reports on the [http://blog.secondlife.com/ Official Linden Blog].&lt;br /&gt;
&lt;br /&gt;
If you cannot log-in after *repeated attempts* this is regarded by Linden Labs as a Showstopper Issue. At present, JIRA is the approved way for Linden Lab to discover widespread log-in difficulties, it will be dealt with promptly, but you should not post a separate issue that you cannot log in, add a comment or vote to the first cannot log-in issue raised on that day.&lt;br /&gt;
&lt;br /&gt;
== Logging in ==&lt;br /&gt;
* Visit https://jira.secondlife.com and click the &#039;Log In&#039; link on the top right of the page&lt;br /&gt;
* On the login page enter your SecondLife Username and Password.&lt;br /&gt;
* This will now load the main Jira page you saw before but it will have more options ie Create Issue and a link to edit your profile as well as some pre-defined filters.&lt;br /&gt;
&lt;br /&gt;
== Bugs &amp;amp; New Features ==&lt;br /&gt;
* Please read [[Bug_Reporting_101|QA Bug Submission Guidelines]] &#039;&#039;&#039;before&#039;&#039;&#039; submitting a a bug.&lt;br /&gt;
* You can also propose new features through JIRA. (JIRA is emerging to succeed the [http://secondlife.com/vote/ Feature Voting Tool] with your help, because it has better search and parallels the way we Lindens internally organize issues. Plus, you can discuss with other Residents.)&lt;br /&gt;
&lt;br /&gt;
== User profile ==&lt;br /&gt;
* Each JIRA user has a &#039;&#039;profile&#039;&#039;. The profile consists of your Username (SL name), Fullname (in our case, also your SL name), and all of the JIRA groups you belong to. For most people, this means &amp;quot;jira-users.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
* The email address associated with your account shall remain anonymous to other users. The address is not visible or configurable at this time. Direct import of your email address from Second Life&#039;s database is currently disabled.&lt;br /&gt;
&lt;br /&gt;
* The JIRA profile is not editable because allowing changes would introduce conflicts with your Second Life account. If you wish to edit account information such as your email address, please login to the [https://secondlife.com/account account management page] at secondlife.com.&lt;br /&gt;
&lt;br /&gt;
== Customizing preferences ==&lt;br /&gt;
* If you want to show more issues per page or change the language JIRA&#039;s displayed in, [https://jira.secondlife.com/secure/UpdateUserPreferences!default.jspa Update User Preferences] after logging in. (Note that e-mail features for newer users may not be available; see [http://jira.secondlife.com/browse/WEB-335 WEB-335] to track.)&lt;br /&gt;
&lt;br /&gt;
== Projects and Components ==&lt;br /&gt;
* &#039;&#039;Projects&#039;&#039; are used to categorize issues into logical groups. &lt;br /&gt;
* &#039;&#039;Components&#039;&#039; are used to specify which part of a system the issue affects. In other words, what is the scope of the problem within a project.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Projects and Components in JIRA&lt;br /&gt;
! Viewer (VWR) !! Service (SVC) !! Website (WEB) !! Miscellaneous (MISC)&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
* Avatar/Character&lt;br /&gt;
* Building (in-world)&lt;br /&gt;
* Chat/IM&lt;br /&gt;
* Crashes&lt;br /&gt;
* Documentation&lt;br /&gt;
* Graphics&lt;br /&gt;
* Internationalization&lt;br /&gt;
* Inventory&lt;br /&gt;
* Land&lt;br /&gt;
* Linden Dollars (L$)&lt;br /&gt;
* Missing Content&lt;br /&gt;
* Performance&lt;br /&gt;
* Permissions&lt;br /&gt;
* Physics&lt;br /&gt;
* Scripting&lt;br /&gt;
* Sound&lt;br /&gt;
* Source Code&lt;br /&gt;
* Stipends&lt;br /&gt;
* User Interface&lt;br /&gt;
* Voice&lt;br /&gt;
|&lt;br /&gt;
* HTTPRequest&lt;br /&gt;
* Internationalization&lt;br /&gt;
* Performance&lt;br /&gt;
* Physics&lt;br /&gt;
* Scripts&lt;br /&gt;
* Simulation&lt;br /&gt;
* Teleport&lt;br /&gt;
* XML-RPC&lt;br /&gt;
|&lt;br /&gt;
* Account summary&lt;br /&gt;
* blog.secondlife.com&lt;br /&gt;
* Developer Directory&lt;br /&gt;
* Events&lt;br /&gt;
* forums.secondlife.com&lt;br /&gt;
* Friends Online&lt;br /&gt;
* Interactive map&lt;br /&gt;
* jira.secondlife.com&lt;br /&gt;
* Land Store&lt;br /&gt;
* lindenlab.com&lt;br /&gt;
* Lindex&lt;br /&gt;
* New account creation&lt;br /&gt;
* Public Data Feeds&lt;br /&gt;
* Public Metrics &amp;amp; Charts&lt;br /&gt;
* secondlife.com&lt;br /&gt;
* teen.secondlife.com&lt;br /&gt;
* wiki.secondlife.com &lt;br /&gt;
|&lt;br /&gt;
* Miscellaneous&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
;Second Life Viewer (VWR): Issues pertaining to the Second Life viewer are reported under this project. &lt;br /&gt;
:&#039;&#039;&#039;Examples&#039;&#039;&#039;:&lt;br /&gt;
:* &amp;quot;My avatar clothing is all black after installing a video driver update&amp;quot; (Component = Avatar/Character) &lt;br /&gt;
:* &amp;quot;Objects in my Inventory do not remain sorted in the correct order after logging out and back in again&amp;quot; (Component = Inventory)&lt;br /&gt;
&lt;br /&gt;
;Second Life Service (SVC): Issues pertaining to the Second Life service are reported here.  &lt;br /&gt;
:&#039;&#039;&#039;Examples&#039;&#039;&#039;:&lt;br /&gt;
:* &amp;quot;Server performance decreases when several avatars teleport into the region at once&amp;quot; (Component = Performance and/or Teleport)&lt;br /&gt;
:* &amp;quot;My scripted objects are not able to talk to the outside world after Second Life grid downtime&amp;quot; (Component = Scripts).&lt;br /&gt;
&lt;br /&gt;
;Second Life Website (WEB): Issues pertaining to the Second Life website are in this project.  &lt;br /&gt;
:&#039;&#039;&#039;Examples&#039;&#039;&#039;:&lt;br /&gt;
:* &amp;quot;Wiki prevents login for users with a dash in their name&amp;quot; (Component = wiki.secondlife.com)&lt;br /&gt;
:* &amp;quot;jira.secondlife.com always forces me to authenticate even if I save my login information&amp;quot; (Component = jira.secondlife.com).&lt;br /&gt;
&lt;br /&gt;
;Second Life Miscellaneous (MISC): Any other type of issue should be reported in the MISC project. &lt;br /&gt;
:&#039;&#039;&#039;Example&#039;&#039;&#039;:&lt;br /&gt;
:* &amp;quot;The TOS does not allow me to edit the viewer source code&amp;quot; (Component = Miscellaneous)&lt;br /&gt;
&lt;br /&gt;
== Security Issues -- a.k.a &amp;quot;the missing Fifth Project&amp;quot; ==&lt;br /&gt;
The Security project in Jira is only accessible by Linden employees. However, you can create a new issue there, and the security team will get immediate notification. See [[security issues]] page for more information about submitting issues and collecting bounties for responsibly reporting valid security issues.&lt;br /&gt;
&lt;br /&gt;
== Who is WorkingOnIt Linden? ==&lt;br /&gt;
When an issue is being worked on, it may be assigned to &amp;quot;WorkingOnIt Linden&amp;quot; to mark its status.  Any Linden has access to the account.  See [[User:WorkingOnIt Linden]] for details.&lt;br /&gt;
&lt;br /&gt;
== Found a bug on JIRA itself! ==&lt;br /&gt;
When you found a bug or other problem (including feature request) on the JIRA itself, Lindens want you to file it on the JIRA run by Atlassian (the developer of JIRA software) by yourself, not thgough the SL public JIRA.  It is available on http://jira.atlassian.com&lt;br /&gt;
&lt;br /&gt;
Lindens also want you to put a link to the issue you filed [[Talk:Issue tracker#Feature requests for Atlassian|here]] if you do so.&lt;br /&gt;
&lt;br /&gt;
= Searching =&lt;br /&gt;
&lt;br /&gt;
== Parameters ==&lt;br /&gt;
* JIRA searching is easy once you know a bit about the parameters you may use.&lt;br /&gt;
* For instructions on searching in JIRA, please visit [http://www.atlassian.com/software/jira/docs/v3.7.1/querysyntax.html JIRA query syntax] and [http://www.atlassian.com/software/jira/docs/v3.7.1/quicksearch.html JIRA quick search].&lt;br /&gt;
&lt;br /&gt;
== Perform a search ==&lt;br /&gt;
* First, click on the &amp;quot;Find Issues&amp;quot; link at the top of the screen.&lt;br /&gt;
* Next, enter the parameters you wish to search for in the search pane on the left-hand side of the screen.&lt;br /&gt;
* As an example, if I wish to search for issues that have not been resolved containing the word &amp;quot;avatar&amp;quot;, I would choose the following parameters:&lt;br /&gt;
** Project = all projects&lt;br /&gt;
** Text search = avatar&lt;br /&gt;
** Resolutions = Unresolved&lt;br /&gt;
* Another sample search would be for any issues that are fixed in the last week in a particular project. For example, I want to find all bugs in the Second Life Viewer project that were resolved between February 1, 2007 and February 14, 2007. I would enter the following parameters:&lt;br /&gt;
** (Optional: Click the &amp;quot;New&amp;quot; link in the search pane to clear settings from any previous searches)&lt;br /&gt;
** Project = Second Life Viewer&lt;br /&gt;
** Resolution = Fixed&lt;br /&gt;
** Updated After = January 31, 2007&lt;br /&gt;
** Updated Before = February 15, 2007&lt;br /&gt;
&lt;br /&gt;
== Saving a search as a Filter ==&lt;br /&gt;
* A search &#039;&#039;filter&#039;&#039; is a saved search that you may share with others.&lt;br /&gt;
* After performing a search as described above, you may save it as a filter by clicking the &amp;quot;Save&amp;quot; link in the Search pane. &lt;br /&gt;
* Name the filter something meaningful, for example &amp;quot;Unresolved avatar bugs in all projects.&amp;quot;&lt;br /&gt;
* Now you can access the search and run it at any time by clicking the &amp;quot;Filter&amp;quot; link in the top right-hand side of the page. This saves time and effort, especially if you frequently run the same complex search and want a handy shortcut!&lt;br /&gt;
&lt;br /&gt;
= Creating bug reports and feature requests =&lt;br /&gt;
&#039;&#039;&#039;If you feel lost and don&#039;t know where to begin, see the easy starter guide, &amp;quot;[http://blog.secondlife.com/2007/07/05/how-to-report-bugs-better/ How to report bugs better]&amp;quot;.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Stay recent ==&lt;br /&gt;
You can check the [[Release Notes]] or [[Beta Release Notes]] to stay current with recent changes to Second Life.  Sometimes, one can discover the context around a new bug, or find that a change was intentional.  For example, not being able to sell your land for L$0 is a feature, not a bug.&lt;br /&gt;
&lt;br /&gt;
Also, you should make sure your video drivers are up to date.  These are normally obtained from the website of your graphics hardware manufacturer, usually either the [http://www.nvidia.com/content/drivers/drivers.asp NVIDIA official site] or the [http://ati.amd.com/support/driver.html ATI official site].  The [http://www.omegadrivers.net/ Omega Drivers] are often-used modified versions of those drivers.&lt;br /&gt;
&lt;br /&gt;
== Determine if the issue has already been submitted ==&lt;br /&gt;
Avoiding duplicate issues is very important.  Sorting through duplicates wastes time and effort (for both Linden Lab staff and fellow residents), and it causes bugs and feature proposals to seem like they are getting less attention than they actually are.  It is more effective to concentrate efforts about the same problem in the same issue, especially since more-active issues get greater priority.&lt;br /&gt;
&lt;br /&gt;
After logging in, you will see the Dashboard. Here you have access to some search filters which give you access to the most up-to-date information on submitted issues. For example, you can click on ones which show all unresolved (unfixed or untested) issues within each project, then begin a text search from there (by editing the filter). Of course you may create and save your own filters at any time, or simply run a new search from the Quick Search box. Either way, it is best practice to search for issues you wish to report in several ways before submitting them!&lt;br /&gt;
&lt;br /&gt;
If you find that your issue was already submitted, you can still do several things to help:&lt;br /&gt;
* Leave a comment containing additional information or details&lt;br /&gt;
* If it&#039;s a bug, possibly another way to reproduce the bug&lt;br /&gt;
* Vote for the issue to express that you feel it is important.&lt;br /&gt;
The more good information there is about a specific issue, the better chance it has for a quick resolution. &lt;br /&gt;
&lt;br /&gt;
== Guidelines ==&lt;br /&gt;
* Submit security-related issues and exploits directly to the security team.  Exploits are bugs that could be used to get an advantage over others, unauthorized access to scripts, unauthorized copying or transferring or modifying of objects that you didn&#039;t create (also called &#039;permissions&#039; bugs), and other bugs that could potentially cause a compromise of the grid or a resident&#039;s privacy.  For the fastest results, contact a Linden in the group &amp;quot;Bug Hunters&amp;quot;, and e-mail your report to security@lindenlab.com.  See the article on [[security issues]].&lt;br /&gt;
* If your issue is urgent (such as lost content), and you have a Premium Account use the phone or live text support. You might get a faster response if you also submit a ticket through the [http://support.secondlife.com support portal], but usually it take over seven days before your ticket is opened.&lt;br /&gt;
* When describing the bug, if possible, try to omit Resident names or other personally-identifying information.  If the bug seems to affect only yourself or very few people, you should consider other ways to find technical support via the [http://support.secondlife.com support portal].&lt;br /&gt;
* The easier we can reproduce the bug, the more quickly it can get fixed.  For example, instead of saying &amp;quot;I crash when I upload random things&amp;quot;, the reproduction should be laid out in specific steps:&lt;br /&gt;
*: Example:&lt;br /&gt;
*:* Click File &amp;gt; Upload Image ($L10)...&lt;br /&gt;
*:* Choose a .TXT file instead of a .JPG file&lt;br /&gt;
*:* Click the Open button &lt;br /&gt;
: Try sending your writeup to a friend, to see if they can follow it!  If your friend can follow the steps, chances are we can too!&lt;br /&gt;
* Consider uploading snapshots, images, videos, crash logs, or any other related files (10MB limit each).  In the above example, you might consider uploading the files you tried to upload that caused the crash.&lt;br /&gt;
* &#039;&#039;&#039;Do not&#039;&#039;&#039; submit more than one issue in a single report.&lt;br /&gt;
* &#039;&#039;&#039;Do&#039;&#039;&#039; search through issues first to ensure yours is not a duplicate.&lt;br /&gt;
&lt;br /&gt;
== Submitting a bug ==&lt;br /&gt;
To create a new bug in JIRA, do the following:&lt;br /&gt;
* Click the &amp;quot;Create New Issue&amp;quot; link in the blue navigation bar towards the top of the screen.  (If you don&#039;t see this, make sure you are [[#Logging in|logged in to JIRA]].)&lt;br /&gt;
&lt;br /&gt;
On the first page:&lt;br /&gt;
* Select a &#039;&#039;&#039;project&#039;&#039;&#039; that most closely matches the kind of bug you are submitting - see [[#Projects and Components]].&lt;br /&gt;
** Reminder: you should submit security-related issues directly to the security team.  See [[security issues]].&lt;br /&gt;
* Select &amp;quot;Bug&amp;quot; as your &#039;&#039;&#039;issue type&#039;&#039;&#039;.&lt;br /&gt;
* Click &amp;quot;Next&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
On the last page:&lt;br /&gt;
* Enter a concise but descriptive &#039;&#039;&#039;summary&#039;&#039;&#039; (title) for the issue&lt;br /&gt;
* Select the &#039;&#039;&#039;priority&#039;&#039;&#039; (severity) of the bug.  For example, a &amp;quot;blocker&amp;quot; bug might render the program useless, but a &amp;quot;small&amp;quot; bug might be merely cosmetic.  Click the icon next to the dropdown for more details.&lt;br /&gt;
* Select &#039;&#039;&#039;components&#039;&#039;&#039; that narrow the scope of the bug.  You can select multiple components by Ctrl-clicking.&lt;br /&gt;
* Choose the &#039;&#039;&#039;versions&#039;&#039;&#039; that the bug effects.  You should only select those versions where you have observed the bug, and only select a &amp;quot;first look&amp;quot; version if the bug &#039;&#039;only&#039;&#039; applies to First Look.&lt;br /&gt;
* The &#039;&#039;&#039;Linden Lab Issue ID&#039;&#039;&#039; should generally be left blank unless you are a Linden.  If you want to reference a support ticket number, that should go in the description, not here.&lt;br /&gt;
* Describe the &#039;&#039;&#039;environment&#039;&#039;&#039; in which the problem occurs, if you have noticed that the bug only occurs with certain hardware or software configurations.  One way to find such information is the About box inside Second Life.  You can guesstimate whether certain facts might be relevant (such as graphics card model for graphics problems, or headset models for voice features) and look for further help in narrowing things down.  If configuration doesn&#039;t seem to matter, you can leave it blank.&lt;br /&gt;
** For example, &amp;quot;Only happens with Mac OS X 10.4.1,&amp;quot; or &amp;quot;Seen only with NVIDIA GeForce Go 7800 card,&amp;quot; etc.&lt;br /&gt;
* Enter a detailed &#039;&#039;&#039;description&#039;&#039;&#039; of the issue, and be sure to include:&lt;br /&gt;
** Steps to reliably reproduce the bug (how to make the bug happen), or at least a description of what seems to lead to the bug, in some detail.  Try to make this as simple as possible while still being specific enough to reproduce the bug.  Simpler reproductions make it easier to narrow down the causes.&lt;br /&gt;
** Observed results (what happens when the bug occurs)&lt;br /&gt;
** Expected results (what behavior you would have expected instead)&lt;br /&gt;
** Anything else which you think might help, such as forum links or blog posts.&lt;br /&gt;
** Again, be as detailed as possible without including personal information!&lt;br /&gt;
* If you have a screenshot or video of the bug, or any other relevant file, you can attach it under &#039;&#039;&#039;attachment&#039;&#039;&#039;.  Note that it has a 10MB size limit per file.  You can also attach additional files later. (See [[Debug Help]] for various ways to provide such additional information.)&lt;br /&gt;
* If you are a programmer and are attaching a patch for the source code, enter the &#039;&#039;&#039;source version&#039;&#039;&#039; the patch is against and check the &#039;&#039;&#039;patch attached&#039;&#039;&#039; box.&lt;br /&gt;
* Finally, click &amp;quot;Create&amp;quot; to create the new issue.&lt;br /&gt;
&lt;br /&gt;
== Submitting a new feature ==&lt;br /&gt;
The process is similar to submitting a bug, with the following differences:&lt;br /&gt;
&lt;br /&gt;
* Select &amp;quot;New Feature&amp;quot; instead of &amp;quot;Bug&amp;quot; as your &#039;&#039;&#039;issue type&#039;&#039;&#039;.&lt;br /&gt;
* Instead of a &amp;quot;reproduction&amp;quot;, clearly describe the desired implementation and functionality of the new feature. Make sure it hasn&#039;t already been done — you can refer to [http://www.slhistory.org/index.php/Release_Notes release notes] for historical context and [http://blog.secondlife.com/ read our blog] to learn more about what we&#039;re doing next.&lt;br /&gt;
&lt;br /&gt;
== Voting for issues ==&lt;br /&gt;
You can vote for new features and bugs that you wish to see resolved, and [https://jira.secondlife.com/secure/IssueNavigator.jspa?mode=hide&amp;amp;requestId=10071 view all issues by # of votes]. JIRA uses [http://en.wikipedia.org/wiki/Approval_voting approval voting], so you can vote for as many (or few) issues as you&#039;d like, and you get 1 vote per issue.&lt;br /&gt;
&lt;br /&gt;
Votes can readily be used as part of our prioritization process. Note that since we need to look at aspects such as feasibility and the time required for implementation, a highly-voted issue isn&#039;t necessarily going to be resolved ahead of a lesser-voted, but more doable one.&lt;br /&gt;
&lt;br /&gt;
== Return to check on issue status ==&lt;br /&gt;
Linden Lab will review issues submitted to jira.secondlife.com on a regular basis. The engineering team may require additional information from the issue reporter, or other contributors, so reviewing all of your created/commented issues regularly will be useful while email support in JIRA is disabled.&lt;br /&gt;
&lt;br /&gt;
Also, when issues are resolved internally the external site will be updated as well, so check your issues for changes on a regular basis.&lt;br /&gt;
&lt;br /&gt;
= Issue States =&lt;br /&gt;
&lt;br /&gt;
== Available states ==&lt;br /&gt;
&lt;br /&gt;
Here is how Linden Lab is using the resolutions:&lt;br /&gt;
&lt;br /&gt;
; Open : This is an issue that belongs to the Assignee to resolve.  The assignee may fix the issue, or kick the issue back to the reporter by marking it &amp;quot;Resolved&amp;quot; (see below)&lt;br /&gt;
; In Progress : This is how a developer signals to everyone that he/she is working on the issue.&lt;br /&gt;
; Reopened : same as &amp;quot;Open&amp;quot;.&lt;br /&gt;
; Resolved : This is an implicit assignment back to the reporter of the issue.  It is not closed yet, but rather in a state of limbo that depends on the resolution.  It&#039;s up to the Reporter to decide whether to reopen an issue, or close it.&lt;br /&gt;
:; Fixed : means that the bug is fixed in a public release of Second Life.&lt;br /&gt;
:; Fix Pending: means that the bug is fixed in a version of the code that should soon be publicly available.&lt;br /&gt;
:; Won&#039;t Fix : means that the assignee doesn&#039;t believe this issue should ever be fixed.&lt;br /&gt;
:; Duplicate : means that there&#039;s some other issue that describes the same problem/idea.&lt;br /&gt;
:; Needs More Info : this issue lacks information &lt;br /&gt;
:; Cannot Reproduce : we&#039;re applying this label pretty liberally.  Please provide a detailed description of how to reproduce a problem.  Issues that can&#039;t be reproduced will eventually be closed.&lt;br /&gt;
:; Misfiled : this issue doesn&#039;t belong in this issue tracker.&lt;br /&gt;
; Closed : The final resting place.&lt;br /&gt;
&lt;br /&gt;
== What&#039;s the difference between the &amp;quot;Fixed&amp;quot; and &amp;quot;Fix Pending&amp;quot; resolutions? ==&lt;br /&gt;
It&#039;s simple:&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;Fixed&amp;quot; means the fix is available in the live Second Life release, &#039;&#039;right now&#039;&#039;.&lt;br /&gt;
* &amp;quot;Fix Pending&amp;quot; means the fix has been made within Linden Lab and &#039;&#039;has not&#039;&#039; been released publicly yet. It may need to undergo extra care, like quality assurance, or requires merging from a [http://en.wikipedia.org/wiki/Branching_%28software%29 branch], before being available to you. Think of it as a &amp;quot;We&#039;re almost there... coming soon!&amp;quot; notice.&lt;br /&gt;
&lt;br /&gt;
= How do I help out? =&lt;br /&gt;
&lt;br /&gt;
Glad you asked!  &lt;br /&gt;
&lt;br /&gt;
== Marking Duplicates ==&lt;br /&gt;
If you notice an newer issue that is a duplicate of an existing issue with a lot more comments, patches, or votes, feel free to choose &amp;quot;Resolve&amp;quot; and choose &amp;quot;Duplicate&amp;quot;.  But when you do this, please also choose &amp;quot;Link&amp;quot;, and then say &amp;quot;This issue duplicates&amp;quot; and enter the main bug number.  This lets everyone keep track of which bugs are duplicates of each other, and which bugs are reported more than others.  This ensures that bugs that are often reported get the most attention, and also allows the duplicates to be reviewed from one central location, to ensure they are truly duplicates.&lt;br /&gt;
&lt;br /&gt;
== Resolving support issues ==&lt;br /&gt;
This one is best left to technically adept users that can spot the difference between a support issue and a bug -- it&#039;s not always a simple matter to figure out.  You should at most &amp;quot;Resolve&amp;quot; a report that seems to be a support issue.  &amp;quot;Resolving&amp;quot; an issue puts the responsibility back on the reporter to provide more information on why the report isn&#039;t a support issue, and is indeed a reproducible bug that an entire class of user experiences.&lt;br /&gt;
&lt;br /&gt;
== Resolving bugs that you can&#039;t reproduce ==&lt;br /&gt;
If you do exactly what they say in the bug, with the same environment, and can&#039;t reproduce the bug, you should resolve the bug.  Be careful, if a bug is related to graphics rendering, and you do not have the same video card, for example, that is not the same environment and you can&#039;t make this determination.  Again this is also best left to technically adept users.&lt;br /&gt;
&lt;br /&gt;
== Reproducing bugs ==&lt;br /&gt;
This one is very important!  If you can create a step-by-step list to reproduce the bug in the bug report, this helps Linden Lab concentrate on bugs that can be verifiably fixed.  Unless a bug can be reproduced, it is impossible to know if it has been fixed or not.  Do what the bug reporter said they were doing, write a detailed step-by-step list of things you did to cause the bug to happen, and add it to the bug saying that you have successfully reproduced the bug.  Such bugs with solid reproductions get higher priority in the development process, and help the Bug Triage Team work more efficiently.&lt;br /&gt;
&lt;br /&gt;
= Related resources =&lt;br /&gt;
Want to learn more about our Issue Tracker?&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;[[Issue Tracker Forum Transcript]]&#039;&#039;&#039; - Info from Rob and Aric Linden on why we have an Issue Tracker, its behind-the-scenes workings, and answers to various questions. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category: Issue Tracker]]&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/RestrainedLifeAPI&amp;diff=60142</id>
		<title>LSL Protocol/RestrainedLifeAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/RestrainedLifeAPI&amp;diff=60142"/>
		<updated>2008-03-26T21:46:11Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Security Advisory|Linden Lab does not support and makes no representations regarding this application.}}&lt;br /&gt;
&lt;br /&gt;
=Restrained Life viewer v1.10.2 Specification=&lt;br /&gt;
&lt;br /&gt;
By [[User:Marine Kelley|Marine Kelley]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Audience==&lt;br /&gt;
&lt;br /&gt;
This document is aimed at people who wish to modify or create their own [[LSL]] scripts to use the functionalities of the [http://realrestraint.blogspot.com RestrainedLife viewer]. It does not, however, explains [[LSL]] concepts such as messages and events, nor universal concepts such as [[UUID]]s.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
The [http://realrestraint.blogspot.com RestrainedLife viewer] is meant to execute certain behaviours when receiving special messages from scripts in-world. These messages are mostly calls to the [[llOwnerSay]]() [[LSL]] function.&lt;br /&gt;
&lt;br /&gt;
==Architecture==&lt;br /&gt;
&lt;br /&gt;
The [http://realrestraint.blogspot.com RestrainedLife viewer] parses every [[llOwnerSay]] call and executes every command beginning with &#039;&#039;&#039;&#039;@&#039;&#039;&#039;&#039;. For instance, a call to [[llOwnerSay]] (&amp;quot;@detach=n&amp;quot;) will tell the viewer that the object sending the message cannot be detached until further notice.&lt;br /&gt;
&lt;br /&gt;
Version &#039;&#039;&#039;1.10&#039;&#039;&#039; and above are able to parse multiple commands in one message, in order to avoid spamming the user who is not using this viewer. The format of a message is therefore :&lt;br /&gt;
&lt;br /&gt;
@&amp;lt;behaviour1&amp;gt;[:option1]=&amp;lt;param1&amp;gt;,&amp;lt;behaviour2&amp;gt;[:option2]=&amp;lt;param2&amp;gt;,...,&amp;lt;behaviourN&amp;gt;[:optionN]=&amp;lt;paramN&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is only one &#039;@&#039; sign, placed at the beginning of the message. The viewer understands this as &amp;quot;this whole [[llOwnerSay]]() is actually a command to execute&amp;quot;, so no need to put a &#039;@&#039; before every command, it wouldn&#039;t even work. If at least one command fails (typo), the viewer says &amp;quot;... fails command : ... &amp;quot; and mentions it all. However correct commands are parsed and executed, only incorrect ones are discarded.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039; : These behaviours are &#039;&#039;&#039;not&#039;&#039;&#039; persistent between sessions, and an object changes [[UUID]] everytime it [[rez]]zes. This means the object must resend its &amp;quot;status&amp;quot; (undetachable, preventing IMs...) in the [[on_rez]] () event as well as when it changes.&lt;br /&gt;
&lt;br /&gt;
==List of commands==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note : These commands are not case-sensitive but are spacing-sensitive. In other words, &amp;quot;@detach = n&amp;quot; will &#039;&#039;&#039;not&#039;&#039;&#039; work.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Automated version checking&#039;&#039;&#039;&#039;&#039; : &amp;quot;@version=&amp;lt;channel_number&amp;gt;&amp;quot;&lt;br /&gt;
Makes the viewer automatically say its version immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039; : when logging in, the [[on_rez]] event of all the attachments occurs way before the avatar can actually send chat messages (about half the way through the login progress bar). This means the timeout should be long enough, like 30 seconds to one minute in order to receive the automatic reply from the viewer.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Manual version checking&#039;&#039;&#039;&#039;&#039; : &amp;quot;@version&amp;quot;&lt;br /&gt;
This command must be sent in IM from an avatar to the user (will not work from objects). The viewer automatically answers its version to the sender in IM, but neither the message nor the answer appears in the user&#039;s IM window, so it&#039;s totally stealthy.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Render an object detachable/nondetachable&#039;&#039;&#039;&#039;&#039; : &amp;quot;@detach=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When called with the &amp;quot;n&amp;quot; option, the object sending this message (which must be an attachment) will be made nondetachable. It can be detached again when the &amp;quot;y&amp;quot; option is called.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent sending chat messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sendchat=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, everything typed on [[channel]] 0 will be discarded. However, emotes and messages beginning with a slash (&#039;/&#039;) will go through, truncated to strings of 30 and 15 characters long respectively (likely to change later). Messages with special signs like ()&amp;quot;-*=_^ are prohibited, and will be discarded. When a period (&#039;.&#039;) is present, the rest of the message is discarded.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add an exception to the emote truncation above&#039;&#039;&#039;&#039;&#039; : &amp;quot;@emote=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding this exception, the emotes are not truncated anymore (however, special signs will still discard the message).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent sending instant messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sendim=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, everything typed in IM will be discarded and a bogus message will be sent to the receiver instead.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the instant message sending prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sendim:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can send IMs to the receiver whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent receiving chat messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvchat=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, everything heard in public chat will be discarded.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the chat message receiving prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvchat:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can hear chat messages from the sender whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent receiving instant messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvim=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, every incoming IM will be discarded and the sender will be notified that the user cannot read them.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the chat message receiving prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvim:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can read instant messages from the sender whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent teleporting to a landmark&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tplm=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, the user cannot use a [[landmark]], pick or any other preset location to [[teleport]] there.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent teleporting to a location&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tploc=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, the user cannot use [[teleport]] to a coordinate by using the [[map]] and such.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent teleporting by a friend&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tplure=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, the user automatically discards any [[teleport]] offer, and the avatar who initiated the offer is notified.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the friend teleport prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tplure:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can be teleported by the avatar whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Unlimit/limit sit-tp&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sittp=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When limited, the avatar cannot sit on a [[prim]] unless it is closer than 1.5 m. This allows cages to be secure, preventing the avatar from warping its position through the walls (unless the prim is too close).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Clear all the rules tied to an object&#039;&#039;&#039;&#039;&#039; : &amp;quot;@clear&amp;quot;&lt;br /&gt;
This command clears all the restrictions and exceptions tied to a particular [[UUID]].&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Clear a subset of the rules tied to an object&#039;&#039;&#039;&#039;&#039; : &amp;quot;@clear=&amp;lt;string&amp;gt;&amp;quot;&lt;br /&gt;
This command clears all the restrictions and exceptions tied to a particular [[UUID]] which name contains &amp;lt;string&amp;gt;. A good example would be &amp;quot;@clear=tp&amp;quot; which clears all the [[teleport]] restrictions and exceptions tied to that object, whereas &amp;quot;@clear=tplure:&amp;quot; would only clear the exceptions to the &amp;quot;teleport-by-friend&amp;quot; restriction&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent editing objects&#039;&#039;&#039;&#039;&#039; : &amp;quot;@edit=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented from editing and deleting objects, the Build &amp;amp; Edit window will refuse to open.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent rezzing inventory&#039;&#039;&#039;&#039;&#039; : &amp;quot;@rez=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented from [[rez]]zing stuff, creating objects, drag-dropping from inventory and dropping attachments will fail.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent wearing clothes&#039;&#039;&#039;&#039;&#039; : @addoutfit[:&amp;lt;part&amp;gt;]=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Where part is :&lt;br /&gt;
 gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin&lt;br /&gt;
If part is not specified, prevents from wearing anything beyond what the avatar is already wearing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent removing clothes&#039;&#039;&#039;&#039;&#039; : @remoutfit[:&amp;lt;part&amp;gt;]=&amp;lt;y/n&amp;gt; (underpants and underwear are kept for teens)&lt;br /&gt;
Where part is :&lt;br /&gt;
 gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin&lt;br /&gt;
If part is not specified, prevents from removing anything in what the avatar is wearing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force removing clothes&#039;&#039;&#039;&#039;&#039; : @remoutfit[:&amp;lt;part&amp;gt;]=force (*)&lt;br /&gt;
Where part is :&lt;br /&gt;
 gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin&lt;br /&gt;
If part is not specified, removes everything.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force removing attachments&#039;&#039;&#039;&#039;&#039; : @detach[:attachpt]=force (*) (underpants and underwear are kept for teens)&lt;br /&gt;
Where part is :&lt;br /&gt;
 chest|skull|left shoulder|right shoulder|left hand|right hand|left foot|right foot|spine|&lt;br /&gt;
 pelvis|mouth|chin|left ear|right ear|left eyeball|right eyeball|nose|r upper arm|r forearm|&lt;br /&gt;
 l upper arm|l forearm|right hip|r upper leg|r lower leg|left hip|l upper leg|l lower leg|stomach|left pec|&lt;br /&gt;
 right pec|center 2|top right|top|top left|center|bottom left|bottom|bottom right&lt;br /&gt;
If part is not specified, removes everything.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Get the list of worn clothes&#039;&#039;&#039;&#039;&#039; : @getoutfit[:part]=&amp;lt;channel_number&amp;gt;&lt;br /&gt;
Makes the viewer automatically answer the current occupation of clothes layers as a list of 0s (empty) and 1s (occupied) immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout.&lt;br /&gt;
&lt;br /&gt;
The list of 0s and 1s corresponds to :&lt;br /&gt;
 gloves,jacket,pants,shirt,shoes,skirt,socks,underpants,undershirt,skin&lt;br /&gt;
in that order.&lt;br /&gt;
&lt;br /&gt;
If a part is specified, answers a single 0 (empty) or 1 (occupied) corresponding to the part.&lt;br /&gt;
 Ex 1 : @getoutfit=2222 =&amp;gt; &amp;quot;0011000111&amp;quot; =&amp;gt; avatar is wearing pants, shirt, underpants and undershirt, and of course a skin.&lt;br /&gt;
 Ex 2 : @getoutfit:socks=2222 =&amp;gt; &amp;quot;0&amp;quot; =&amp;gt; the avatar is not wearing socks.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Get the list of worn attachments&#039;&#039;&#039;&#039;&#039; : @getattach[:attachpt]=&amp;lt;channel_number&amp;gt;&lt;br /&gt;
Makes the viewer automatically answer the current occupation of attachment points as a list of 0s (empty) and 1s (occupied) immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout.&lt;br /&gt;
&lt;br /&gt;
The list of 0s and 1s corresponds to :&lt;br /&gt;
 none,chest,skull,left shoulder,right shoulder,left hand,right hand,left foot,right foot,spine,&lt;br /&gt;
 pelvis,mouth,chin,left ear,right ear,left eyeball,right eyeball,nose,r upper arm,r forearm,&lt;br /&gt;
 l upper,arm,l forearm,right hip,r upper leg,r lower leg,left hip,l upper leg,l lower leg,stomach,left pec,&lt;br /&gt;
 right pec,center 2,top right,top,top left,center,bottom left,bottom,bottom right&lt;br /&gt;
in that order.&lt;br /&gt;
&lt;br /&gt;
If an attachment point is specified, answers a single 0 (empty) or 1 (occupied) corresponding to the point.&lt;br /&gt;
 Ex 1 : @getattach=2222 =&amp;gt; &amp;quot;011000011010000000000000100100000000101&amp;quot; =&amp;gt; avatar is wearing attachments on &lt;br /&gt;
 chest, skull, left and right foot, pelvis, l and r lower leg, HUD bottom left and HUD bottom right.&lt;br /&gt;
 Ex 2 : @getattach:chest=2222 =&amp;gt; &amp;quot;1&amp;quot; =&amp;gt; avatar is wearing something on the chest.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note&#039;&#039; : The first character (&amp;quot;none&amp;quot;) is always &#039;0&#039;, so the index of each attach point in the string is &#039;&#039;&#039;exactly equal&#039;&#039;&#039; to the corresponding ATTACH_* macro in LSL. For instance, the index 9 in the string is ATTACH_BACK (which means &amp;quot;spine&amp;quot;). Remember the indices start at zero.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent using inventory&#039;&#039;&#039;&#039;&#039; : @showinv=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Forces the [[inventory]] windows to close and stay closed.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent reading notecards&#039;&#039;&#039;&#039;&#039; : @viewnote=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Prevents from opening [[notecards]] but does not close the ones already open.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent standing up&#039;&#039;&#039;&#039;&#039; : @unsit=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Hides the Stand up button.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force sit on an object&#039;&#039;&#039;&#039;&#039; : @sit:&amp;lt;UUID&amp;gt;=force (*)&lt;br /&gt;
Does not work if the user is prevented from sit-tping and further than 1.5 meters away, or when prevented from unsitting.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force unsit&#039;&#039;&#039;&#039;&#039; : @unsit=force (*)&lt;br /&gt;
Self-explanatory but for some reason it randomly fails, so don&#039;t rely on it for now. Further testing is needed.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent using any chat channel but certain channels&#039;&#039;&#039;&#039;&#039; : @sendchannel[:&amp;lt;channel&amp;gt;]=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Complimentary of @sendchat, this command prevents the user from sending messages on non-public [[channel]]s. If channel is specified, it becomes an exception to the aforementioned restriction.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Get the list of restrictions the avatar is currently submitted to&#039;&#039;&#039;&#039;&#039; : @getstatus[:&amp;lt;part_of_rule&amp;gt;]=&amp;lt;channel&amp;gt;&lt;br /&gt;
Makes the viewer automatically answer the list of rules the avatar is currently under, only for the object containing the script issuing that command, immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout. The answer is a list of rules, separated by slashes (&#039;/&#039;).&lt;br /&gt;
&lt;br /&gt;
This command is useful for people who write scripts that may conflict with other scripts in the same object (for instance : third-party plugins). Conflict do not occur in different objects, that&#039;s why this command only applies to the object calling it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;part_of_rule&amp;gt; is the name of a rule, or a part of it, useful if the script only needs to know about a certain restriction.&lt;br /&gt;
&lt;br /&gt;
 Example : If the avatar is under tploc, tplure, tplm and sittp, here is what the script would get :&lt;br /&gt;
 @getstatus=2222  =&amp;gt;  tploc/tplure/tplm/sittp&lt;br /&gt;
 @getstatus:sittp=2222  =&amp;gt;  sittp&lt;br /&gt;
 @getstatus:tpl=2222  =&amp;gt;  tploc/tplure/tplm  (because &amp;quot;tpl&amp;quot; is part of &amp;quot;tploc&amp;quot;, &amp;quot;tplure&amp;quot; and &amp;quot;tplm&amp;quot; but not &amp;quot;sittp&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(*) Silently discarded if the user is prevented from doing so by the corresponding restriction. This is on purpose.&lt;br /&gt;
    Ex : Force detach won&#039;t work if the object is undetachable. Force undress won&#039;t work if the user is prevented from undressing.&lt;br /&gt;
&lt;br /&gt;
==Important note about the global behaviours such as sendchat==&lt;br /&gt;
Such behaviours are global, which means they don&#039;t depend on a particular object. However, they are triggered by objects with a set [[UUID]] which can change, and several objects can add the same behaviour, which will be stored several times as the [[UUID]]s are different. &lt;br /&gt;
&lt;br /&gt;
This has a nice side effect : when wearing 2 locked devices that prevent chat, it is necessary to unlock them both to be able to chat again. But it has a nasty side effect, too : if the item changes [[UUID]] (for instance it was derezzed and rezzed again), and it doesn&#039;t allow chat beforehand, then the user will have to wait a short moment because the rule stays &amp;quot;orphaned&amp;quot; (its [[UUID]] is defunct) until the &#039;&#039;&#039;garbage collector&#039;&#039;&#039; kicks in.&lt;br /&gt;
&lt;br /&gt;
Therefore : &lt;br /&gt;
&#039;&#039;&#039;ALWAYS DEACTIVATE A BEHAVIOUR WHEN THE OBJECT THAT HAS ACTIVATED IT DEREZZES FOR ANY REASON BESIDES LOGGING OUT ! &amp;quot;@CLEAR&amp;quot; IS YOUR FRIEND !&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==For your information==&lt;br /&gt;
Here is how it works internally, for a better understanding of the gotchas you may encounter :&lt;br /&gt;
* Each command is parsed into a &#039;&#039;&#039;Behaviour&#039;&#039;&#039; (ex: &amp;quot;remoutfit&amp;quot;), an &#039;&#039;&#039;Option&#039;&#039;&#039; (ex: &amp;quot;shirt&amp;quot;) and a &#039;&#039;&#039;Param&#039;&#039;&#039; (ex: &amp;quot;force&amp;quot;) and comes from an [[UUID]] (the unique identifier of the emitting object).&lt;br /&gt;
&lt;br /&gt;
* There are two types of commands : &#039;&#039;&#039;one-shot&#039;&#039;&#039; commands (those which Param is &amp;quot;force&amp;quot; and those which Param is a number such as the channel number of a &amp;quot;version&amp;quot; call) and &#039;&#039;&#039;rules&#039;&#039;&#039; (those which Param is &amp;quot;y&amp;quot;, &amp;quot;n&amp;quot;, &amp;quot;add&amp;quot; or &amp;quot;rem&amp;quot;). &amp;quot;clear&amp;quot; is special but can be seen as a one-shot command.&lt;br /&gt;
&lt;br /&gt;
* Parameters &amp;quot;n&amp;quot; and &amp;quot;add&amp;quot; are &#039;&#039;&#039;exactly equal&#039;&#039;&#039; and are treated &#039;&#039;&#039;exactly the same way&#039;&#039;&#039;, they are just &#039;&#039;&#039;synonyms&#039;&#039;&#039;. Same goes for &amp;quot;y&amp;quot; and &amp;quot;rem&amp;quot;. The only purpose is to distinguish rules (&amp;quot;sendchannel=n&amp;quot;) from exceptions (&amp;quot;sendchannel:8=add&amp;quot;) in a script for clarity.&lt;br /&gt;
&lt;br /&gt;
* Rules are stored inside a table linking the [[UUID]] of the emitter to the rule itself. They are &#039;&#039;&#039;added&#039;&#039;&#039; when receiving a &amp;quot;n&amp;quot;/&amp;quot;add&amp;quot; Param, and &#039;&#039;&#039;removed&#039;&#039;&#039; when receiving a &amp;quot;y&amp;quot;/&amp;quot;rem&amp;quot; Param.&lt;br /&gt;
If &#039;&#039;&#039;&#039;&#039;UUID1&#039;&#039;&#039;&#039;&#039; is a collar and &#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; is a gag :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID1&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, tploc, tplm, tplure, sittp&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, sendim, sendim:(keyholder)&lt;br /&gt;
&lt;br /&gt;
Those two rules mean that the user cannot send IMs except to their keyholder, and cannot TP at all. Those two items are not detachable. Now if the collar sends &amp;quot;@sendim=n&amp;quot;, the table becomes :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID1&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, tploc, tplm, tplure, sittp, sendim&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, sendim, sendim:(keyholder)&lt;br /&gt;
&lt;br /&gt;
If it sends &amp;quot;@sendim=n&amp;quot; a second time nothing changes, as there is a check for its existence prior to adding it. If the gag is unlocked and detached, either it sends a &amp;quot;@clear&amp;quot; or the garbage collector kicks in so the rules linked to &#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; disappear. However, the avatar is still unable to send IMs even to their keyholder, as the exception has disappeared as well. This is because rules linked to one object don&#039;t conflict with rules linked to another one.&lt;br /&gt;
&lt;br /&gt;
* One-shot commands, on the other hand, are executed on-the-fly and are not stored.&lt;br /&gt;
&lt;br /&gt;
* When logging on, the avatar stays non-operational (cannot chat, cannot move) for some time, while the user sees the progress bar. However, worn scripted objects [[rez]] in the meantime and start sending rules and commands before the viewer can execute them. Therefore it stores them in a buffer and executes them only when the user is given controls (when the progress bar disappears).&lt;br /&gt;
&lt;br /&gt;
* The viewer periodically (every N seconds) checks all its rules and removes the ones linked to an [[UUID]] that does not exist around anymore (&amp;quot;garbage collector&amp;quot;). This means that rules issued by an &#039;&#039;&#039;unworn&#039;&#039;&#039; owned object will be discarded as soon as the avatar [[teleports]] elsewhere.&lt;br /&gt;
&lt;br /&gt;
[[Category:Third Party Client]]&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=File:Ambox_emblem_question_yellow.svg&amp;diff=60141</id>
		<title>File:Ambox emblem question yellow.svg</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=File:Ambox_emblem_question_yellow.svg&amp;diff=60141"/>
		<updated>2008-03-26T21:42:22Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: From http://upload.wikimedia.org/wikipedia/commons/b/b5/Ambox_emblem_question_yellow.svg.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;From http://upload.wikimedia.org/wikipedia/commons/b/b5/Ambox_emblem_question_yellow.svg.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/RestrainedLifeAPI&amp;diff=60140</id>
		<title>LSL Protocol/RestrainedLifeAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/RestrainedLifeAPI&amp;diff=60140"/>
		<updated>2008-03-26T21:41:47Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Security Advisory|Linden Lab does not support and makes no representations regarding this application.}}&lt;br /&gt;
&lt;br /&gt;
=Restrained Life viewer v1.10.2 Specification=&lt;br /&gt;
&lt;br /&gt;
By [[User:Marine Kelley|Marine Kelley]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Audience==&lt;br /&gt;
&lt;br /&gt;
This document is aimed at people who wish to modify or create their own [[LSL]] scripts to use the functionalities of the [http://realrestraint.blogspot.com RestrainedLife viewer]. It does not, however, explains [[LSL]] concepts such as messages and events, nor universal concepts such as [[UUID]]s.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
The [http://realrestraint.blogspot.com RestrainedLife viewer] is meant to execute certain behaviours when receiving special messages from scripts in-world. These messages are mostly calls to the [[llOwnerSay]]() [[LSL]] function.&lt;br /&gt;
&lt;br /&gt;
==Architecture==&lt;br /&gt;
&lt;br /&gt;
The [http://realrestraint.blogspot.com RestrainedLife viewer] parses every [[llOwnerSay]] call and executes every command beginning with &#039;&#039;&#039;&#039;@&#039;&#039;&#039;&#039;. For instance, a call to [[llOwnerSay]] (&amp;quot;@detach=n&amp;quot;) will tell the viewer that the object sending the message cannot be detached until further notice.&lt;br /&gt;
&lt;br /&gt;
Version &#039;&#039;&#039;1.10&#039;&#039;&#039; and above are able to parse multiple commands in one message, in order to avoid spamming the user who is not using this viewer. The format of a message is therefore :&lt;br /&gt;
&lt;br /&gt;
@&amp;lt;behaviour1&amp;gt;[:option1]=&amp;lt;param1&amp;gt;,&amp;lt;behaviour2&amp;gt;[:option2]=&amp;lt;param2&amp;gt;,...,&amp;lt;behaviourN&amp;gt;[:optionN]=&amp;lt;paramN&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is only one &#039;@&#039; sign, placed at the beginning of the message. The viewer understands this as &amp;quot;this whole [[llOwnerSay]]() is actually a command to execute&amp;quot;, so no need to put a &#039;@&#039; before every command, it wouldn&#039;t even work. If at least one command fails (typo), the viewer says &amp;quot;... fails command : ... &amp;quot; and mentions it all. However correct commands are parsed and executed, only incorrect ones are discarded.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039; : These behaviours are &#039;&#039;&#039;not&#039;&#039;&#039; persistent between sessions, and an object changes [[UUID]] everytime it [[rez]]zes. This means the object must resend its &amp;quot;status&amp;quot; (undetachable, preventing IMs...) in the [[on_rez]] () event as well as when it changes.&lt;br /&gt;
&lt;br /&gt;
==List of commands==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note : These commands are not case-sensitive but are spacing-sensitive. In other words, &amp;quot;@detach = n&amp;quot; will &#039;&#039;&#039;not&#039;&#039;&#039; work.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Automated version checking&#039;&#039;&#039;&#039;&#039; : &amp;quot;@version=&amp;lt;channel_number&amp;gt;&amp;quot;&lt;br /&gt;
Makes the viewer automatically say its version immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039; : when logging in, the [[on_rez]] event of all the attachments occurs way before the avatar can actually send chat messages (about half the way through the login progress bar). This means the timeout should be long enough, like 30 seconds to one minute in order to receive the automatic reply from the viewer.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Manual version checking&#039;&#039;&#039;&#039;&#039; : &amp;quot;@version&amp;quot;&lt;br /&gt;
This command must be sent in IM from an avatar to the user (will not work from objects). The viewer automatically answers its version to the sender in IM, but neither the message nor the answer appears in the user&#039;s IM window, so it&#039;s totally stealthy.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Render an object detachable/nondetachable&#039;&#039;&#039;&#039;&#039; : &amp;quot;@detach=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When called with the &amp;quot;n&amp;quot; option, the object sending this message (which must be an attachment) will be made nondetachable. It can be detached again when the &amp;quot;y&amp;quot; option is called.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent sending chat messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sendchat=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, everything typed on [[channel]] 0 will be discarded. However, emotes and messages beginning with a slash (&#039;/&#039;) will go through, truncated to strings of 30 and 15 characters long respectively (likely to change later). Messages with special signs like ()&amp;quot;-*=_^ are prohibited, and will be discarded. When a period (&#039;.&#039;) is present, the rest of the message is discarded.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add an exception to the emote truncation above&#039;&#039;&#039;&#039;&#039; : &amp;quot;@emote=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding this exception, the emotes are not truncated anymore (however, special signs will still discard the message).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent sending instant messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sendim=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, everything typed in IM will be discarded and a bogus message will be sent to the receiver instead.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the instant message sending prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sendim:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can send IMs to the receiver whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent receiving chat messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvchat=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, everything heard in public chat will be discarded.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the chat message receiving prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvchat:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can hear chat messages from the sender whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent receiving instant messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvim=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, every incoming IM will be discarded and the sender will be notified that the user cannot read them.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the chat message receiving prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvim:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can read instant messages from the sender whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent teleporting to a landmark&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tplm=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, the user cannot use a [[landmark]], pick or any other preset location to [[teleport]] there.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent teleporting to a location&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tploc=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, the user cannot use [[teleport]] to a coordinate by using the [[map]] and such.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent teleporting by a friend&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tplure=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, the user automatically discards any [[teleport]] offer, and the avatar who initiated the offer is notified.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the friend teleport prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tplure:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can be teleported by the avatar whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Unlimit/limit sit-tp&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sittp=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When limited, the avatar cannot sit on a [[prim]] unless it is closer than 1.5 m. This allows cages to be secure, preventing the avatar from warping its position through the walls (unless the prim is too close).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Clear all the rules tied to an object&#039;&#039;&#039;&#039;&#039; : &amp;quot;@clear&amp;quot;&lt;br /&gt;
This command clears all the restrictions and exceptions tied to a particular [[UUID]].&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Clear a subset of the rules tied to an object&#039;&#039;&#039;&#039;&#039; : &amp;quot;@clear=&amp;lt;string&amp;gt;&amp;quot;&lt;br /&gt;
This command clears all the restrictions and exceptions tied to a particular [[UUID]] which name contains &amp;lt;string&amp;gt;. A good example would be &amp;quot;@clear=tp&amp;quot; which clears all the [[teleport]] restrictions and exceptions tied to that object, whereas &amp;quot;@clear=tplure:&amp;quot; would only clear the exceptions to the &amp;quot;teleport-by-friend&amp;quot; restriction&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent editing objects&#039;&#039;&#039;&#039;&#039; : &amp;quot;@edit=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented from editing and deleting objects, the Build &amp;amp; Edit window will refuse to open.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent rezzing inventory&#039;&#039;&#039;&#039;&#039; : &amp;quot;@rez=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented from [[rez]]zing stuff, creating objects, drag-dropping from inventory and dropping attachments will fail.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent wearing clothes&#039;&#039;&#039;&#039;&#039; : @addoutfit[:&amp;lt;part&amp;gt;]=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Where part is :&lt;br /&gt;
 gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin&lt;br /&gt;
If part is not specified, prevents from wearing anything beyond what the avatar is already wearing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent removing clothes&#039;&#039;&#039;&#039;&#039; : @remoutfit[:&amp;lt;part&amp;gt;]=&amp;lt;y/n&amp;gt; (underpants and underwear are kept for teens)&lt;br /&gt;
Where part is :&lt;br /&gt;
 gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin&lt;br /&gt;
If part is not specified, prevents from removing anything in what the avatar is wearing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force removing clothes&#039;&#039;&#039;&#039;&#039; : @remoutfit[:&amp;lt;part&amp;gt;]=force (*)&lt;br /&gt;
Where part is :&lt;br /&gt;
 gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin&lt;br /&gt;
If part is not specified, removes everything.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force removing attachments&#039;&#039;&#039;&#039;&#039; : @detach[:attachpt]=force (*) (underpants and underwear are kept for teens)&lt;br /&gt;
Where part is :&lt;br /&gt;
 chest|skull|left shoulder|right shoulder|left hand|right hand|left foot|right foot|spine|&lt;br /&gt;
 pelvis|mouth|chin|left ear|right ear|left eyeball|right eyeball|nose|r upper arm|r forearm|&lt;br /&gt;
 l upper arm|l forearm|right hip|r upper leg|r lower leg|left hip|l upper leg|l lower leg|stomach|left pec|&lt;br /&gt;
 right pec|center 2|top right|top|top left|center|bottom left|bottom|bottom right&lt;br /&gt;
If part is not specified, removes everything.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Get the list of worn clothes&#039;&#039;&#039;&#039;&#039; : @getoutfit[:part]=&amp;lt;channel_number&amp;gt;&lt;br /&gt;
Makes the viewer automatically answer the current occupation of clothes layers as a list of 0s (empty) and 1s (occupied) immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout.&lt;br /&gt;
&lt;br /&gt;
The list of 0s and 1s corresponds to :&lt;br /&gt;
 gloves,jacket,pants,shirt,shoes,skirt,socks,underpants,undershirt,skin&lt;br /&gt;
in that order.&lt;br /&gt;
&lt;br /&gt;
If a part is specified, answers a single 0 (empty) or 1 (occupied) corresponding to the part.&lt;br /&gt;
 Ex 1 : @getoutfit=2222 =&amp;gt; &amp;quot;0011000111&amp;quot; =&amp;gt; avatar is wearing pants, shirt, underpants and undershirt, and of course a skin.&lt;br /&gt;
 Ex 2 : @getoutfit:socks=2222 =&amp;gt; &amp;quot;0&amp;quot; =&amp;gt; the avatar is not wearing socks.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Get the list of worn attachments&#039;&#039;&#039;&#039;&#039; : @getattach[:attachpt]=&amp;lt;channel_number&amp;gt;&lt;br /&gt;
Makes the viewer automatically answer the current occupation of attachment points as a list of 0s (empty) and 1s (occupied) immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout.&lt;br /&gt;
&lt;br /&gt;
The list of 0s and 1s corresponds to :&lt;br /&gt;
 none,chest,skull,left shoulder,right shoulder,left hand,right hand,left foot,right foot,spine,&lt;br /&gt;
 pelvis,mouth,chin,left ear,right ear,left eyeball,right eyeball,nose,r upper arm,r forearm,&lt;br /&gt;
 l upper,arm,l forearm,right hip,r upper leg,r lower leg,left hip,l upper leg,l lower leg,stomach,left pec,&lt;br /&gt;
 right pec,center 2,top right,top,top left,center,bottom left,bottom,bottom right&lt;br /&gt;
in that order.&lt;br /&gt;
&lt;br /&gt;
If an attachment point is specified, answers a single 0 (empty) or 1 (occupied) corresponding to the point.&lt;br /&gt;
 Ex 1 : @getattach=2222 =&amp;gt; &amp;quot;011000011010000000000000100100000000101&amp;quot; =&amp;gt; avatar is wearing attachments on &lt;br /&gt;
 chest, skull, left and right foot, pelvis, l and r lower leg, HUD bottom left and HUD bottom right.&lt;br /&gt;
 Ex 2 : @getattach:chest=2222 =&amp;gt; &amp;quot;1&amp;quot; =&amp;gt; avatar is wearing something on the chest.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note&#039;&#039; : The first character (&amp;quot;none&amp;quot;) is always &#039;0&#039;, so the index of each attach point in the string is &#039;&#039;&#039;exactly equal&#039;&#039;&#039; to the corresponding ATTACH_* macro in LSL. For instance, the index 9 in the string is ATTACH_BACK (which means &amp;quot;spine&amp;quot;). Remember the indices start at zero.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent using inventory&#039;&#039;&#039;&#039;&#039; : @showinv=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Forces the [[inventory]] windows to close and stay closed.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent reading notecards&#039;&#039;&#039;&#039;&#039; : @viewnote=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Prevents from opening [[notecards]] but does not close the ones already open.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent standing up&#039;&#039;&#039;&#039;&#039; : @unsit=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Hides the Stand up button.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force sit on an object&#039;&#039;&#039;&#039;&#039; : @sit:&amp;lt;UUID&amp;gt;=force (*)&lt;br /&gt;
Does not work if the user is prevented from sit-tping and further than 1.5 meters away, or when prevented from unsitting.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force unsit&#039;&#039;&#039;&#039;&#039; : @unsit=force (*)&lt;br /&gt;
Self-explanatory but for some reason it randomly fails, so don&#039;t rely on it for now. Further testing is needed.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent using any chat channel but certain channels&#039;&#039;&#039;&#039;&#039; : @sendchannel[:&amp;lt;channel&amp;gt;]=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Complimentary of @sendchat, this command prevents the user from sending messages on non-public [[channel]]s. If channel is specified, it becomes an exception to the aforementioned restriction.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Get the list of restrictions the avatar is currently submitted to&#039;&#039;&#039;&#039;&#039; : @getstatus[:&amp;lt;part_of_rule&amp;gt;]=&amp;lt;channel&amp;gt;&lt;br /&gt;
Makes the viewer automatically answer the list of rules the avatar is currently under, only for the object containing the script issuing that command, immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout. The answer is a list of rules, separated by slashes (&#039;/&#039;).&lt;br /&gt;
&lt;br /&gt;
This command is useful for people who write scripts that may conflict with other scripts in the same object (for instance : third-party plugins). Conflict do not occur in different objects, that&#039;s why this command only applies to the object calling it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;part_of_rule&amp;gt; is the name of a rule, or a part of it, useful if the script only needs to know about a certain restriction.&lt;br /&gt;
&lt;br /&gt;
 Example : If the avatar is under tploc, tplure, tplm and sittp, here is what the script would get :&lt;br /&gt;
 @getstatus=2222  =&amp;gt;  tploc/tplure/tplm/sittp&lt;br /&gt;
 @getstatus:sittp=2222  =&amp;gt;  sittp&lt;br /&gt;
 @getstatus:tpl=2222  =&amp;gt;  tploc/tplure/tplm  (because &amp;quot;tpl&amp;quot; is part of &amp;quot;tploc&amp;quot;, &amp;quot;tplure&amp;quot; and &amp;quot;tplm&amp;quot; but not &amp;quot;sittp&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(*) Silently discarded if the user is prevented from doing so by the corresponding restriction. This is on purpose.&lt;br /&gt;
    Ex : Force detach won&#039;t work if the object is undetachable. Force undress won&#039;t work if the user is prevented from undressing.&lt;br /&gt;
&lt;br /&gt;
==Important note about the global behaviours such as sendchat==&lt;br /&gt;
Such behaviours are global, which means they don&#039;t depend on a particular object. However, they are triggered by objects with a set [[UUID]] which can change, and several objects can add the same behaviour, which will be stored several times as the [[UUID]]s are different. &lt;br /&gt;
&lt;br /&gt;
This has a nice side effect : when wearing 2 locked devices that prevent chat, it is necessary to unlock them both to be able to chat again. But it has a nasty side effect, too : if the item changes [[UUID]] (for instance it was derezzed and rezzed again), and it doesn&#039;t allow chat beforehand, then the user will have to wait a short moment because the rule stays &amp;quot;orphaned&amp;quot; (its [[UUID]] is defunct) until the &#039;&#039;&#039;garbage collector&#039;&#039;&#039; kicks in.&lt;br /&gt;
&lt;br /&gt;
Therefore : &lt;br /&gt;
&#039;&#039;&#039;ALWAYS DEACTIVATE A BEHAVIOUR WHEN THE OBJECT THAT HAS ACTIVATED IT DEREZZES FOR ANY REASON BESIDES LOGGING OUT ! &amp;quot;@CLEAR&amp;quot; IS YOUR FRIEND !&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==For your information==&lt;br /&gt;
Here is how it works internally, for a better understanding of the gotchas you may encounter :&lt;br /&gt;
* Each command is parsed into a &#039;&#039;&#039;Behaviour&#039;&#039;&#039; (ex: &amp;quot;remoutfit&amp;quot;), an &#039;&#039;&#039;Option&#039;&#039;&#039; (ex: &amp;quot;shirt&amp;quot;) and a &#039;&#039;&#039;Param&#039;&#039;&#039; (ex: &amp;quot;force&amp;quot;) and comes from an [[UUID]] (the unique identifier of the emitting object).&lt;br /&gt;
&lt;br /&gt;
* There are two types of commands : &#039;&#039;&#039;one-shot&#039;&#039;&#039; commands (those which Param is &amp;quot;force&amp;quot; and those which Param is a number such as the channel number of a &amp;quot;version&amp;quot; call) and &#039;&#039;&#039;rules&#039;&#039;&#039; (those which Param is &amp;quot;y&amp;quot;, &amp;quot;n&amp;quot;, &amp;quot;add&amp;quot; or &amp;quot;rem&amp;quot;). &amp;quot;clear&amp;quot; is special but can be seen as a one-shot command.&lt;br /&gt;
&lt;br /&gt;
* Parameters &amp;quot;n&amp;quot; and &amp;quot;add&amp;quot; are &#039;&#039;&#039;exactly equal&#039;&#039;&#039; and are treated &#039;&#039;&#039;exactly the same way&#039;&#039;&#039;, they are just &#039;&#039;&#039;synonyms&#039;&#039;&#039;. Same goes for &amp;quot;y&amp;quot; and &amp;quot;rem&amp;quot;. The only purpose is to distinguish rules (&amp;quot;sendchannel=n&amp;quot;) from exceptions (&amp;quot;sendchannel:8=add&amp;quot;) in a script for clarity.&lt;br /&gt;
&lt;br /&gt;
* Rules are stored inside a table linking the [[UUID]] of the emitter to the rule itself. They are &#039;&#039;&#039;added&#039;&#039;&#039; when receiving a &amp;quot;n&amp;quot;/&amp;quot;add&amp;quot; Param, and &#039;&#039;&#039;removed&#039;&#039;&#039; when receiving a &amp;quot;y&amp;quot;/&amp;quot;rem&amp;quot; Param.&lt;br /&gt;
If &#039;&#039;&#039;&#039;&#039;UUID1&#039;&#039;&#039;&#039;&#039; is a collar and &#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; is a gag :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID1&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, tploc, tplm, tplure, sittp&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, sendim, sendim:(keyholder)&lt;br /&gt;
&lt;br /&gt;
Those two rules mean that the user cannot send IMs except to their keyholder, and cannot TP at all. Those two items are not detachable. Now if the collar sends &amp;quot;@sendim=n&amp;quot;, the table becomes :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID1&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, tploc, tplm, tplure, sittp, sendim&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, sendim, sendim:(keyholder)&lt;br /&gt;
&lt;br /&gt;
If it sends &amp;quot;@sendim=n&amp;quot; a second time nothing changes, as there is a check for its existence prior to adding it. If the gag is unlocked and detached, either it sends a &amp;quot;@clear&amp;quot; or the garbage collector kicks in so the rules linked to &#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; disappear. However, the avatar is still unable to send IMs even to their keyholder, as the exception has disappeared as well. This is because rules linked to one object don&#039;t conflict with rules linked to another one.&lt;br /&gt;
&lt;br /&gt;
* One-shot commands, on the other hand, are executed on-the-fly and are not stored.&lt;br /&gt;
&lt;br /&gt;
* When logging on, the avatar stays non-operational (cannot chat, cannot move) for some time, while the user sees the progress bar. However, worn scripted objects [[rez]] in the meantime and start sending rules and commands before the viewer can execute them. Therefore it stores them in a buffer and executes them only when the user is given controls (when the progress bar disappears).&lt;br /&gt;
&lt;br /&gt;
* The viewer periodically (every N seconds) checks all its rules and removes the ones linked to an [[UUID]] that does not exist around anymore (&amp;quot;garbage collector&amp;quot;). This means that rules issued by an &#039;&#039;&#039;unworn&#039;&#039;&#039; owned object will be discarded as soon as the avatar [[teleports]] elsewhere.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/RestrainedLifeAPI&amp;diff=60139</id>
		<title>LSL Protocol/RestrainedLifeAPI</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/RestrainedLifeAPI&amp;diff=60139"/>
		<updated>2008-03-26T21:38:42Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* Restrained Life viewer v1.10.2 Specification */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Security Advisory|Linden Lab does not support and makes no representations regarding this applications.}}&lt;br /&gt;
&lt;br /&gt;
=Restrained Life viewer v1.10.2 Specification=&lt;br /&gt;
&lt;br /&gt;
By [[User:Marine Kelley|Marine Kelley]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Audience==&lt;br /&gt;
&lt;br /&gt;
This document is aimed at people who wish to modify or create their own [[LSL]] scripts to use the functionalities of the [http://realrestraint.blogspot.com RestrainedLife viewer]. It does not, however, explains [[LSL]] concepts such as messages and events, nor universal concepts such as [[UUID]]s.&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
&lt;br /&gt;
The [http://realrestraint.blogspot.com RestrainedLife viewer] is meant to execute certain behaviours when receiving special messages from scripts in-world. These messages are mostly calls to the [[llOwnerSay]]() [[LSL]] function.&lt;br /&gt;
&lt;br /&gt;
==Architecture==&lt;br /&gt;
&lt;br /&gt;
The [http://realrestraint.blogspot.com RestrainedLife viewer] parses every [[llOwnerSay]] call and executes every command beginning with &#039;&#039;&#039;&#039;@&#039;&#039;&#039;&#039;. For instance, a call to [[llOwnerSay]] (&amp;quot;@detach=n&amp;quot;) will tell the viewer that the object sending the message cannot be detached until further notice.&lt;br /&gt;
&lt;br /&gt;
Version &#039;&#039;&#039;1.10&#039;&#039;&#039; and above are able to parse multiple commands in one message, in order to avoid spamming the user who is not using this viewer. The format of a message is therefore :&lt;br /&gt;
&lt;br /&gt;
@&amp;lt;behaviour1&amp;gt;[:option1]=&amp;lt;param1&amp;gt;,&amp;lt;behaviour2&amp;gt;[:option2]=&amp;lt;param2&amp;gt;,...,&amp;lt;behaviourN&amp;gt;[:optionN]=&amp;lt;paramN&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that there is only one &#039;@&#039; sign, placed at the beginning of the message. The viewer understands this as &amp;quot;this whole [[llOwnerSay]]() is actually a command to execute&amp;quot;, so no need to put a &#039;@&#039; before every command, it wouldn&#039;t even work. If at least one command fails (typo), the viewer says &amp;quot;... fails command : ... &amp;quot; and mentions it all. However correct commands are parsed and executed, only incorrect ones are discarded.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039; : These behaviours are &#039;&#039;&#039;not&#039;&#039;&#039; persistent between sessions, and an object changes [[UUID]] everytime it [[rez]]zes. This means the object must resend its &amp;quot;status&amp;quot; (undetachable, preventing IMs...) in the [[on_rez]] () event as well as when it changes.&lt;br /&gt;
&lt;br /&gt;
==List of commands==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note : These commands are not case-sensitive but are spacing-sensitive. In other words, &amp;quot;@detach = n&amp;quot; will &#039;&#039;&#039;not&#039;&#039;&#039; work.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Automated version checking&#039;&#039;&#039;&#039;&#039; : &amp;quot;@version=&amp;lt;channel_number&amp;gt;&amp;quot;&lt;br /&gt;
Makes the viewer automatically say its version immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning&#039;&#039;&#039; : when logging in, the [[on_rez]] event of all the attachments occurs way before the avatar can actually send chat messages (about half the way through the login progress bar). This means the timeout should be long enough, like 30 seconds to one minute in order to receive the automatic reply from the viewer.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Manual version checking&#039;&#039;&#039;&#039;&#039; : &amp;quot;@version&amp;quot;&lt;br /&gt;
This command must be sent in IM from an avatar to the user (will not work from objects). The viewer automatically answers its version to the sender in IM, but neither the message nor the answer appears in the user&#039;s IM window, so it&#039;s totally stealthy.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Render an object detachable/nondetachable&#039;&#039;&#039;&#039;&#039; : &amp;quot;@detach=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When called with the &amp;quot;n&amp;quot; option, the object sending this message (which must be an attachment) will be made nondetachable. It can be detached again when the &amp;quot;y&amp;quot; option is called.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent sending chat messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sendchat=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, everything typed on [[channel]] 0 will be discarded. However, emotes and messages beginning with a slash (&#039;/&#039;) will go through, truncated to strings of 30 and 15 characters long respectively (likely to change later). Messages with special signs like ()&amp;quot;-*=_^ are prohibited, and will be discarded. When a period (&#039;.&#039;) is present, the rest of the message is discarded.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add an exception to the emote truncation above&#039;&#039;&#039;&#039;&#039; : &amp;quot;@emote=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding this exception, the emotes are not truncated anymore (however, special signs will still discard the message).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent sending instant messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sendim=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, everything typed in IM will be discarded and a bogus message will be sent to the receiver instead.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the instant message sending prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sendim:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can send IMs to the receiver whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent receiving chat messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvchat=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, everything heard in public chat will be discarded.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the chat message receiving prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvchat:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can hear chat messages from the sender whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent receiving instant messages&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvim=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, every incoming IM will be discarded and the sender will be notified that the user cannot read them.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the chat message receiving prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@recvim:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can read instant messages from the sender whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent teleporting to a landmark&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tplm=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, the user cannot use a [[landmark]], pick or any other preset location to [[teleport]] there.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent teleporting to a location&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tploc=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, the user cannot use [[teleport]] to a coordinate by using the [[map]] and such.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent teleporting by a friend&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tplure=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented, the user automatically discards any [[teleport]] offer, and the avatar who initiated the offer is notified.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Remove/add exceptions to the friend teleport prevention&#039;&#039;&#039;&#039;&#039; : &amp;quot;@tplure:&amp;lt;UUID&amp;gt;=&amp;lt;rem/add&amp;gt;&amp;quot;&lt;br /&gt;
When adding an exception, the user can be teleported by the avatar whose [[UUID]] is specified in the command. This overrides the prevention for this avatar only (there is no limit to the number of exceptions), don&#039;t forget to remove it when it becomes obsolete.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Unlimit/limit sit-tp&#039;&#039;&#039;&#039;&#039; : &amp;quot;@sittp=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When limited, the avatar cannot sit on a [[prim]] unless it is closer than 1.5 m. This allows cages to be secure, preventing the avatar from warping its position through the walls (unless the prim is too close).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Clear all the rules tied to an object&#039;&#039;&#039;&#039;&#039; : &amp;quot;@clear&amp;quot;&lt;br /&gt;
This command clears all the restrictions and exceptions tied to a particular [[UUID]].&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Clear a subset of the rules tied to an object&#039;&#039;&#039;&#039;&#039; : &amp;quot;@clear=&amp;lt;string&amp;gt;&amp;quot;&lt;br /&gt;
This command clears all the restrictions and exceptions tied to a particular [[UUID]] which name contains &amp;lt;string&amp;gt;. A good example would be &amp;quot;@clear=tp&amp;quot; which clears all the [[teleport]] restrictions and exceptions tied to that object, whereas &amp;quot;@clear=tplure:&amp;quot; would only clear the exceptions to the &amp;quot;teleport-by-friend&amp;quot; restriction&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent editing objects&#039;&#039;&#039;&#039;&#039; : &amp;quot;@edit=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented from editing and deleting objects, the Build &amp;amp; Edit window will refuse to open.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent rezzing inventory&#039;&#039;&#039;&#039;&#039; : &amp;quot;@rez=&amp;lt;y/n&amp;gt;&amp;quot;&lt;br /&gt;
When prevented from [[rez]]zing stuff, creating objects, drag-dropping from inventory and dropping attachments will fail.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent wearing clothes&#039;&#039;&#039;&#039;&#039; : @addoutfit[:&amp;lt;part&amp;gt;]=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Where part is :&lt;br /&gt;
 gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin&lt;br /&gt;
If part is not specified, prevents from wearing anything beyond what the avatar is already wearing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent removing clothes&#039;&#039;&#039;&#039;&#039; : @remoutfit[:&amp;lt;part&amp;gt;]=&amp;lt;y/n&amp;gt; (underpants and underwear are kept for teens)&lt;br /&gt;
Where part is :&lt;br /&gt;
 gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin&lt;br /&gt;
If part is not specified, prevents from removing anything in what the avatar is wearing.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force removing clothes&#039;&#039;&#039;&#039;&#039; : @remoutfit[:&amp;lt;part&amp;gt;]=force (*)&lt;br /&gt;
Where part is :&lt;br /&gt;
 gloves|jacket|pants|shirt|shoes|skirt|socks|underpants|undershirt|skin&lt;br /&gt;
If part is not specified, removes everything.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force removing attachments&#039;&#039;&#039;&#039;&#039; : @detach[:attachpt]=force (*) (underpants and underwear are kept for teens)&lt;br /&gt;
Where part is :&lt;br /&gt;
 chest|skull|left shoulder|right shoulder|left hand|right hand|left foot|right foot|spine|&lt;br /&gt;
 pelvis|mouth|chin|left ear|right ear|left eyeball|right eyeball|nose|r upper arm|r forearm|&lt;br /&gt;
 l upper arm|l forearm|right hip|r upper leg|r lower leg|left hip|l upper leg|l lower leg|stomach|left pec|&lt;br /&gt;
 right pec|center 2|top right|top|top left|center|bottom left|bottom|bottom right&lt;br /&gt;
If part is not specified, removes everything.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Get the list of worn clothes&#039;&#039;&#039;&#039;&#039; : @getoutfit[:part]=&amp;lt;channel_number&amp;gt;&lt;br /&gt;
Makes the viewer automatically answer the current occupation of clothes layers as a list of 0s (empty) and 1s (occupied) immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout.&lt;br /&gt;
&lt;br /&gt;
The list of 0s and 1s corresponds to :&lt;br /&gt;
 gloves,jacket,pants,shirt,shoes,skirt,socks,underpants,undershirt,skin&lt;br /&gt;
in that order.&lt;br /&gt;
&lt;br /&gt;
If a part is specified, answers a single 0 (empty) or 1 (occupied) corresponding to the part.&lt;br /&gt;
 Ex 1 : @getoutfit=2222 =&amp;gt; &amp;quot;0011000111&amp;quot; =&amp;gt; avatar is wearing pants, shirt, underpants and undershirt, and of course a skin.&lt;br /&gt;
 Ex 2 : @getoutfit:socks=2222 =&amp;gt; &amp;quot;0&amp;quot; =&amp;gt; the avatar is not wearing socks.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Get the list of worn attachments&#039;&#039;&#039;&#039;&#039; : @getattach[:attachpt]=&amp;lt;channel_number&amp;gt;&lt;br /&gt;
Makes the viewer automatically answer the current occupation of attachment points as a list of 0s (empty) and 1s (occupied) immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout.&lt;br /&gt;
&lt;br /&gt;
The list of 0s and 1s corresponds to :&lt;br /&gt;
 none,chest,skull,left shoulder,right shoulder,left hand,right hand,left foot,right foot,spine,&lt;br /&gt;
 pelvis,mouth,chin,left ear,right ear,left eyeball,right eyeball,nose,r upper arm,r forearm,&lt;br /&gt;
 l upper,arm,l forearm,right hip,r upper leg,r lower leg,left hip,l upper leg,l lower leg,stomach,left pec,&lt;br /&gt;
 right pec,center 2,top right,top,top left,center,bottom left,bottom,bottom right&lt;br /&gt;
in that order.&lt;br /&gt;
&lt;br /&gt;
If an attachment point is specified, answers a single 0 (empty) or 1 (occupied) corresponding to the point.&lt;br /&gt;
 Ex 1 : @getattach=2222 =&amp;gt; &amp;quot;011000011010000000000000100100000000101&amp;quot; =&amp;gt; avatar is wearing attachments on &lt;br /&gt;
 chest, skull, left and right foot, pelvis, l and r lower leg, HUD bottom left and HUD bottom right.&lt;br /&gt;
 Ex 2 : @getattach:chest=2222 =&amp;gt; &amp;quot;1&amp;quot; =&amp;gt; avatar is wearing something on the chest.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note&#039;&#039; : The first character (&amp;quot;none&amp;quot;) is always &#039;0&#039;, so the index of each attach point in the string is &#039;&#039;&#039;exactly equal&#039;&#039;&#039; to the corresponding ATTACH_* macro in LSL. For instance, the index 9 in the string is ATTACH_BACK (which means &amp;quot;spine&amp;quot;). Remember the indices start at zero.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent using inventory&#039;&#039;&#039;&#039;&#039; : @showinv=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Forces the [[inventory]] windows to close and stay closed.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent reading notecards&#039;&#039;&#039;&#039;&#039; : @viewnote=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Prevents from opening [[notecards]] but does not close the ones already open.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent standing up&#039;&#039;&#039;&#039;&#039; : @unsit=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Hides the Stand up button.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force sit on an object&#039;&#039;&#039;&#039;&#039; : @sit:&amp;lt;UUID&amp;gt;=force (*)&lt;br /&gt;
Does not work if the user is prevented from sit-tping and further than 1.5 meters away, or when prevented from unsitting.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Force unsit&#039;&#039;&#039;&#039;&#039; : @unsit=force (*)&lt;br /&gt;
Self-explanatory but for some reason it randomly fails, so don&#039;t rely on it for now. Further testing is needed.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Allow/prevent using any chat channel but certain channels&#039;&#039;&#039;&#039;&#039; : @sendchannel[:&amp;lt;channel&amp;gt;]=&amp;lt;y/n&amp;gt;&lt;br /&gt;
Complimentary of @sendchat, this command prevents the user from sending messages on non-public [[channel]]s. If channel is specified, it becomes an exception to the aforementioned restriction.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;&#039;&#039;Get the list of restrictions the avatar is currently submitted to&#039;&#039;&#039;&#039;&#039; : @getstatus[:&amp;lt;part_of_rule&amp;gt;]=&amp;lt;channel&amp;gt;&lt;br /&gt;
Makes the viewer automatically answer the list of rules the avatar is currently under, only for the object containing the script issuing that command, immediately on the chat channel number &amp;lt;channel_number&amp;gt; that the script can listen to. Always use a positive integer. Remember that regular viewers do not answer anything at all so remove the listener after a timeout. The answer is a list of rules, separated by slashes (&#039;/&#039;).&lt;br /&gt;
&lt;br /&gt;
This command is useful for people who write scripts that may conflict with other scripts in the same object (for instance : third-party plugins). Conflict do not occur in different objects, that&#039;s why this command only applies to the object calling it.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;part_of_rule&amp;gt; is the name of a rule, or a part of it, useful if the script only needs to know about a certain restriction.&lt;br /&gt;
&lt;br /&gt;
 Example : If the avatar is under tploc, tplure, tplm and sittp, here is what the script would get :&lt;br /&gt;
 @getstatus=2222  =&amp;gt;  tploc/tplure/tplm/sittp&lt;br /&gt;
 @getstatus:sittp=2222  =&amp;gt;  sittp&lt;br /&gt;
 @getstatus:tpl=2222  =&amp;gt;  tploc/tplure/tplm  (because &amp;quot;tpl&amp;quot; is part of &amp;quot;tploc&amp;quot;, &amp;quot;tplure&amp;quot; and &amp;quot;tplm&amp;quot; but not &amp;quot;sittp&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(*) Silently discarded if the user is prevented from doing so by the corresponding restriction. This is on purpose.&lt;br /&gt;
    Ex : Force detach won&#039;t work if the object is undetachable. Force undress won&#039;t work if the user is prevented from undressing.&lt;br /&gt;
&lt;br /&gt;
==Important note about the global behaviours such as sendchat==&lt;br /&gt;
Such behaviours are global, which means they don&#039;t depend on a particular object. However, they are triggered by objects with a set [[UUID]] which can change, and several objects can add the same behaviour, which will be stored several times as the [[UUID]]s are different. &lt;br /&gt;
&lt;br /&gt;
This has a nice side effect : when wearing 2 locked devices that prevent chat, it is necessary to unlock them both to be able to chat again. But it has a nasty side effect, too : if the item changes [[UUID]] (for instance it was derezzed and rezzed again), and it doesn&#039;t allow chat beforehand, then the user will have to wait a short moment because the rule stays &amp;quot;orphaned&amp;quot; (its [[UUID]] is defunct) until the &#039;&#039;&#039;garbage collector&#039;&#039;&#039; kicks in.&lt;br /&gt;
&lt;br /&gt;
Therefore : &lt;br /&gt;
&#039;&#039;&#039;ALWAYS DEACTIVATE A BEHAVIOUR WHEN THE OBJECT THAT HAS ACTIVATED IT DEREZZES FOR ANY REASON BESIDES LOGGING OUT ! &amp;quot;@CLEAR&amp;quot; IS YOUR FRIEND !&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==For your information==&lt;br /&gt;
Here is how it works internally, for a better understanding of the gotchas you may encounter :&lt;br /&gt;
* Each command is parsed into a &#039;&#039;&#039;Behaviour&#039;&#039;&#039; (ex: &amp;quot;remoutfit&amp;quot;), an &#039;&#039;&#039;Option&#039;&#039;&#039; (ex: &amp;quot;shirt&amp;quot;) and a &#039;&#039;&#039;Param&#039;&#039;&#039; (ex: &amp;quot;force&amp;quot;) and comes from an [[UUID]] (the unique identifier of the emitting object).&lt;br /&gt;
&lt;br /&gt;
* There are two types of commands : &#039;&#039;&#039;one-shot&#039;&#039;&#039; commands (those which Param is &amp;quot;force&amp;quot; and those which Param is a number such as the channel number of a &amp;quot;version&amp;quot; call) and &#039;&#039;&#039;rules&#039;&#039;&#039; (those which Param is &amp;quot;y&amp;quot;, &amp;quot;n&amp;quot;, &amp;quot;add&amp;quot; or &amp;quot;rem&amp;quot;). &amp;quot;clear&amp;quot; is special but can be seen as a one-shot command.&lt;br /&gt;
&lt;br /&gt;
* Parameters &amp;quot;n&amp;quot; and &amp;quot;add&amp;quot; are &#039;&#039;&#039;exactly equal&#039;&#039;&#039; and are treated &#039;&#039;&#039;exactly the same way&#039;&#039;&#039;, they are just &#039;&#039;&#039;synonyms&#039;&#039;&#039;. Same goes for &amp;quot;y&amp;quot; and &amp;quot;rem&amp;quot;. The only purpose is to distinguish rules (&amp;quot;sendchannel=n&amp;quot;) from exceptions (&amp;quot;sendchannel:8=add&amp;quot;) in a script for clarity.&lt;br /&gt;
&lt;br /&gt;
* Rules are stored inside a table linking the [[UUID]] of the emitter to the rule itself. They are &#039;&#039;&#039;added&#039;&#039;&#039; when receiving a &amp;quot;n&amp;quot;/&amp;quot;add&amp;quot; Param, and &#039;&#039;&#039;removed&#039;&#039;&#039; when receiving a &amp;quot;y&amp;quot;/&amp;quot;rem&amp;quot; Param.&lt;br /&gt;
If &#039;&#039;&#039;&#039;&#039;UUID1&#039;&#039;&#039;&#039;&#039; is a collar and &#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; is a gag :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID1&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, tploc, tplm, tplure, sittp&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, sendim, sendim:(keyholder)&lt;br /&gt;
&lt;br /&gt;
Those two rules mean that the user cannot send IMs except to their keyholder, and cannot TP at all. Those two items are not detachable. Now if the collar sends &amp;quot;@sendim=n&amp;quot;, the table becomes :&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID1&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, tploc, tplm, tplure, sittp, sendim&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; =&amp;gt; detach, sendim, sendim:(keyholder)&lt;br /&gt;
&lt;br /&gt;
If it sends &amp;quot;@sendim=n&amp;quot; a second time nothing changes, as there is a check for its existence prior to adding it. If the gag is unlocked and detached, either it sends a &amp;quot;@clear&amp;quot; or the garbage collector kicks in so the rules linked to &#039;&#039;&#039;&#039;&#039;UUID2&#039;&#039;&#039;&#039;&#039; disappear. However, the avatar is still unable to send IMs even to their keyholder, as the exception has disappeared as well. This is because rules linked to one object don&#039;t conflict with rules linked to another one.&lt;br /&gt;
&lt;br /&gt;
* One-shot commands, on the other hand, are executed on-the-fly and are not stored.&lt;br /&gt;
&lt;br /&gt;
* When logging on, the avatar stays non-operational (cannot chat, cannot move) for some time, while the user sees the progress bar. However, worn scripted objects [[rez]] in the meantime and start sending rules and commands before the viewer can execute them. Therefore it stores them in a buffer and executes them only when the user is given controls (when the progress bar disappears).&lt;br /&gt;
&lt;br /&gt;
* The viewer periodically (every N seconds) checks all its rules and removes the ones linked to an [[UUID]] that does not exist around anymore (&amp;quot;garbage collector&amp;quot;). This means that rules issued by an &#039;&#039;&#039;unworn&#039;&#039;&#039; owned object will be discarded as soon as the avatar [[teleports]] elsewhere.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=File:Ambox_emblem_question.svg&amp;diff=60134</id>
		<title>File:Ambox emblem question.svg</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=File:Ambox_emblem_question.svg&amp;diff=60134"/>
		<updated>2008-03-26T21:29:44Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: From http://commons.wikimedia.org/wiki/Image:Ambox_emblem_question.svg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;From http://commons.wikimedia.org/wiki/Image:Ambox_emblem_question.svg&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=File:Emblem-important-yellow.svg&amp;diff=60132</id>
		<title>File:Emblem-important-yellow.svg</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=File:Emblem-important-yellow.svg&amp;diff=60132"/>
		<updated>2008-03-26T21:21:42Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: From http://commons.wikimedia.org/wiki/Image:Emblem-important-yellow.svg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;From http://commons.wikimedia.org/wiki/Image:Emblem-important-yellow.svg&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=File:Emblem-important-red.svg&amp;diff=60131</id>
		<title>File:Emblem-important-red.svg</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=File:Emblem-important-red.svg&amp;diff=60131"/>
		<updated>2008-03-26T21:20:48Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: From http://commons.wikimedia.org/wiki/Image:Emblem-important-red.svg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;From http://commons.wikimedia.org/wiki/Image:Emblem-important-red.svg&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=File:Emblem-important.svg&amp;diff=60130</id>
		<title>File:Emblem-important.svg</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=File:Emblem-important.svg&amp;diff=60130"/>
		<updated>2008-03-26T21:16:16Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: From http://en.wikipedia.org/wiki/Image:Emblem-important.svg&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;From http://en.wikipedia.org/wiki/Image:Emblem-important.svg&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Template:Security_Advisory&amp;diff=60113</id>
		<title>Template:Security Advisory</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Template:Security_Advisory&amp;diff=60113"/>
		<updated>2008-03-26T19:43:37Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: New page: {{#vardefine:header|{{#var:header}} &amp;lt;div id=&amp;quot;box&amp;quot;&amp;gt; {{{!}} cellspacing=&amp;quot;3&amp;quot; cellpadding=&amp;quot;3&amp;quot; width=&amp;quot;100%&amp;quot; style=&amp;quot;background:#660000;&amp;quot; {{!}} style=&amp;quot;color:white;&amp;quot; title=&amp;quot;Security Advisory&amp;quot; {{!}...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#vardefine:header|{{#var:header}}&lt;br /&gt;
&amp;lt;div id=&amp;quot;box&amp;quot;&amp;gt;&lt;br /&gt;
{{{!}} cellspacing=&amp;quot;3&amp;quot; cellpadding=&amp;quot;3&amp;quot; width=&amp;quot;100%&amp;quot; style=&amp;quot;background:#660000;&amp;quot;&lt;br /&gt;
{{!}} style=&amp;quot;color:white;&amp;quot; title=&amp;quot;Security Advisory&amp;quot; {{!}} &#039;&#039;&#039;Security Advisory&#039;&#039;&#039;&lt;br /&gt;
{{!}}-&lt;br /&gt;
{{!}} bgcolor=&amp;quot;white&amp;quot; {{!}}&lt;br /&gt;
{{{1}}}&lt;br /&gt;
{{!}}}&lt;br /&gt;
&amp;lt;/div&amp;gt;}}{{#if:{{{inline|}}}&amp;lt;noinclude&amp;gt;t&amp;lt;/noinclude&amp;gt;|{{#var:header}}}}&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Mulib/Examples&amp;diff=54258</id>
		<title>Mulib/Examples</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Mulib/Examples&amp;diff=54258"/>
		<updated>2008-02-15T19:08:01Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* Chat Server */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Mulib Examples =&lt;br /&gt;
&lt;br /&gt;
These are some short examples to give a flavor of using [[mulib]].  You can find all the example code in the examples directory of a mulib checkout.&lt;br /&gt;
&lt;br /&gt;
== hello world ==&lt;br /&gt;
&lt;br /&gt;
The following program will bring up a webserver listening on port 8080 which can respond to a single request, &amp;quot;GET /&amp;quot;, with the response &amp;quot;hello, world&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;# hello_world.py:&lt;br /&gt;
from mulib import mu&lt;br /&gt;
&lt;br /&gt;
from eventlet import api, httpd&lt;br /&gt;
&lt;br /&gt;
class HelloWorld(mu.Resource):&lt;br /&gt;
    def handle_get(self, req):&lt;br /&gt;
        req.write(&amp;quot;hello, world\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    root = HelloWorld()&lt;br /&gt;
&lt;br /&gt;
    httpd.server(&lt;br /&gt;
        api.tcp_listener((&#039;0.0.0.0&#039;, 8080)),&lt;br /&gt;
        mu.SiteMap(root))&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== CGI ===&lt;br /&gt;
You can treat this resource as a [http://en.wikipedia.org/wiki/Common_Gateway_Interface CGI], by writing a second, wrapper, file that refers to it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;# hello_world.cgi:&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
from mulib import cgiadapter&lt;br /&gt;
&lt;br /&gt;
cgiadapter.run_as_cgi(&#039;hello_world&#039;, &#039;HelloWorld&#039;)&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure your web server to execute hello_world.cgi, and you should be able to interact with it just like the standalone version.&lt;br /&gt;
&lt;br /&gt;
== stacked ==&lt;br /&gt;
&lt;br /&gt;
Stacked is a pure REST server, and you can use it to traverse native python objects like &amp;lt;code&amp;gt;dicts&amp;lt;/code&amp;gt;.  You invoke these special capabilities of Stacked by placing a python dict or list in the resource hierarchy instead of a mu.Resource, in this case at the root.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;from mulib import mu&lt;br /&gt;
&lt;br /&gt;
from eventlet import api, httpd&lt;br /&gt;
&lt;br /&gt;
root = {&#039;&#039;:&#039;hello, world\n&#039;,&lt;br /&gt;
        &#039;other&#039;:&amp;quot;hello, other\n&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
httpd.server(api.tcp_listener((&#039;0.0.0.0&#039;, 8080)), mu.SiteMap(root))&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then access this dictionary as a REST resource, e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
 &amp;gt; curl http://localhost:8080/     &lt;br /&gt;
 hello, world&lt;br /&gt;
 &amp;gt; curl http://localhost:8080/other&lt;br /&gt;
 hello, other&lt;br /&gt;
 &amp;gt; curl -X PUT -d &amp;quot;the new data&amp;quot; http://localhost:8080/third&lt;br /&gt;
 &amp;gt; curl http://localhost:8080/third&lt;br /&gt;
 the new data&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mu/stacked can do content negotiation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
 &amp;gt; curl -X PUT -H &amp;quot;Content-type: application/json&amp;quot; -d &#039;{&amp;quot;hi&amp;quot;: &amp;quot;there&amp;quot;}&#039; http://localhost:8080/fourth&lt;br /&gt;
 &amp;gt; curl http://localhost:8080/fourth/hi&lt;br /&gt;
 there&lt;br /&gt;
 &amp;gt; curl -H &amp;quot;Accept: application/json&amp;quot; http://localhost:8080/fourth&lt;br /&gt;
 {&#039;hi&#039;: &#039;there&#039;}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; This means that anyone who has access to your stacked web service can modify the data in your process!  In the future we might have a &#039;read-only&#039; implementation.&lt;br /&gt;
&lt;br /&gt;
== Chat Server ==&lt;br /&gt;
[http://www.evilchuck.com/ EvilChuck] wrote a nifty [http://www.evilchuck.com/2008/02/toy-chat-server-with-eventlet-and-mulib.html toy chat server] that we will partially reproduce here at his permission. &lt;br /&gt;
&lt;br /&gt;
Through tacked, and coros, we can tie a &amp;lt;code&amp;gt;ChatMessage&amp;lt;/code&amp;gt; instance to the &#039;&#039;/listen&#039;&#039; url:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;&lt;br /&gt;
from mulib import mu, stacked, resources&lt;br /&gt;
from eventlet import api, httpd, coros, util&lt;br /&gt;
&lt;br /&gt;
util.wrap_socket_with_coroutine_socket()&lt;br /&gt;
&lt;br /&gt;
chat_listener = coros.event()&lt;br /&gt;
&lt;br /&gt;
class ChatMessage(mu.Resource):&lt;br /&gt;
    &amp;quot;&amp;quot;&amp;quot;A Rsource to handle receiving chat messages&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
    def handle_post(self, request):&lt;br /&gt;
        &amp;quot;&amp;quot;&amp;quot;POST to send chat messages&lt;br /&gt;
        expects nick and message as POST arguments&amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
        nick = request.get_arg(&#039;nick&#039;)&lt;br /&gt;
        message = request.get_arg(&#039;message&#039;).strip()&lt;br /&gt;
        if message:&lt;br /&gt;
            # Send the chat message to all who are listening&lt;br /&gt;
            chat_listener.send(&amp;quot;%s: %s&amp;quot; % (nick, message))&lt;br /&gt;
            # Reset the listener so that it can receive more messages &lt;br /&gt;
            chat_listener.reset()&lt;br /&gt;
        request.write(&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
root = {&lt;br /&gt;
        &#039;chat&#039; : resources.File(&#039;chat.html&#039;),   # /chat -&amp;gt; Load chat.html&lt;br /&gt;
        &#039;listen&#039; : chat_listener,               # /listen -&amp;gt; Wait for new msgs &lt;br /&gt;
        &#039;message&#039; : ChatMessage(),              # /message -&amp;gt; Send a message&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
# Start the server&lt;br /&gt;
httpd.server(&lt;br /&gt;
    api.tcp_listener((&#039;0.0.0.0&#039;, 5000)),&lt;br /&gt;
    mu.SiteMap(root), max_http_version=&amp;quot;HTTP/1.0&amp;quot;&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And with some fancy html which is served up through the &amp;lt;code&amp;gt;resources.File&amp;lt;/code&amp;gt; we get:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;html&amp;gt;&lt;br /&gt;
  &amp;lt;head&amp;gt;&lt;br /&gt;
    &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;http://yui.yahooapis.com/2.4.1/build/reset-fonts-grids/reset-fonts-grids.css&amp;quot; type=&amp;quot;text/css&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;style&amp;gt;&lt;br /&gt;
      #hd, #bd, #ft { border: 1px solid #808080;}&lt;br /&gt;
      #hd h1 { margin-left: 5px; font-size: 120%; }&lt;br /&gt;
      #bd { min-height: 350px; }&lt;br /&gt;
      body { position: relative; }&lt;br /&gt;
      .bd { text-align: left; }&lt;br /&gt;
      input { width: 100%; }&lt;br /&gt;
    &amp;lt;/style&amp;gt;&lt;br /&gt;
  &amp;lt;/head&amp;gt;&lt;br /&gt;
  &amp;lt;body&amp;gt;&lt;br /&gt;
  &amp;lt;div id=&amp;quot;doc&amp;quot; class=&amp;quot;yui-t7&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;div id=&amp;quot;hd&amp;quot;&amp;gt;&amp;lt;h1&amp;gt;Web Chat&amp;lt;/h1&amp;gt;&amp;lt;/div&amp;gt; &lt;br /&gt;
    &amp;lt;div id=&amp;quot;bd&amp;quot;&amp;gt; &lt;br /&gt;
      &amp;lt;div class=&amp;quot;yui-g&amp;quot;&amp;gt; &lt;br /&gt;
        &amp;lt;div id=&amp;quot;chat_text&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt; &lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;ft&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;input type=&amp;quot;text&amp;quot; maxlength=&amp;quot;256&amp;quot; id=&amp;quot;chat_message&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt; &lt;br /&gt;
  &amp;lt;/body&amp;gt;&lt;br /&gt;
  &amp;lt;script src=&amp;quot;http://yui.yahooapis.com/2.4.1/build/yahoo/yahoo-min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt; &lt;br /&gt;
  &amp;lt;script src=&amp;quot;http://yui.yahooapis.com/2.4.1/build/event/event-min.js&amp;quot; &amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;script src=&amp;quot;http://yui.yahooapis.com/2.4.1/build/dom/dom-min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;script src=&amp;quot;http://yui.yahooapis.com/2.4.1/build/connection/connection-min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  &amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
    YAHOO.util.Event.onDOMReady(function () {&lt;br /&gt;
      // Set up a random nickname for the user&lt;br /&gt;
      var nick = &#039;User-&#039; + Math.round(Math.random()*10000);&lt;br /&gt;
      var handleReturn = function (type, args, obj) {&lt;br /&gt;
        // Handler to run when the Enter key is pressed&lt;br /&gt;
        var el = document.getElementById(&amp;quot;chat_message&amp;quot;);&lt;br /&gt;
        if (el.value) {&lt;br /&gt;
          // Send the message to the server&lt;br /&gt;
          var postData = &amp;quot;nick=&amp;quot;+escape(nick)+&amp;quot;&amp;amp;message=&amp;quot;+escape(el.value);&lt;br /&gt;
          YAHOO.util.Connect.asyncRequest(&#039;POST&#039;,&#039;/message&#039;, {&lt;br /&gt;
            success : function(o) {&lt;br /&gt;
              el.value = &#039;&#039;;&lt;br /&gt;
              },&lt;br /&gt;
          }, postData);&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      var listen = function () {&lt;br /&gt;
        // Listens for incoming messages&lt;br /&gt;
        YAHOO.util.Connect.asyncRequest(&#039;GET&#039;, &#039;/listen&#039;, {&lt;br /&gt;
          success: function (o) {&lt;br /&gt;
            if (o.status == 200) {&lt;br /&gt;
              var el = document.getElementById(&amp;quot;chat_text&amp;quot;);&lt;br /&gt;
              el.innerHTML += o.responseText + &#039;&amp;lt;BR/&amp;gt;&#039;;&lt;br /&gt;
              listen();&lt;br /&gt;
            }&lt;br /&gt;
            else if (o.status == 202) {&lt;br /&gt;
              // 202 is returned when the connection has timed out&lt;br /&gt;
              listen();&lt;br /&gt;
            }&lt;br /&gt;
          }&lt;br /&gt;
        });&lt;br /&gt;
      };&lt;br /&gt;
      // Register the key listener to listen for the Enter key&lt;br /&gt;
      var keyListener = new YAHOO.util.KeyListener(&lt;br /&gt;
          document, {keys: 13}, handleReturn);&lt;br /&gt;
      keyListener.enable();&lt;br /&gt;
      // Start listening for incoming messages&lt;br /&gt;
      listen();&lt;br /&gt;
    });&lt;br /&gt;
  &amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To test it out, put both files in the same directory, launch chat.py, and browse to http://localhost:5000/chat&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Mulib/Examples&amp;diff=54254</id>
		<title>Mulib/Examples</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Mulib/Examples&amp;diff=54254"/>
		<updated>2008-02-15T18:46:55Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Mulib Examples =&lt;br /&gt;
&lt;br /&gt;
These are some short examples to give a flavor of using [[mulib]].  You can find all the example code in the examples directory of a mulib checkout.&lt;br /&gt;
&lt;br /&gt;
== hello world ==&lt;br /&gt;
&lt;br /&gt;
The following program will bring up a webserver listening on port 8080 which can respond to a single request, &amp;quot;GET /&amp;quot;, with the response &amp;quot;hello, world&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;# hello_world.py:&lt;br /&gt;
from mulib import mu&lt;br /&gt;
&lt;br /&gt;
from eventlet import api, httpd&lt;br /&gt;
&lt;br /&gt;
class HelloWorld(mu.Resource):&lt;br /&gt;
    def handle_get(self, req):&lt;br /&gt;
        req.write(&amp;quot;hello, world\n&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    root = HelloWorld()&lt;br /&gt;
&lt;br /&gt;
    httpd.server(&lt;br /&gt;
        api.tcp_listener((&#039;0.0.0.0&#039;, 8080)),&lt;br /&gt;
        mu.SiteMap(root))&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== CGI ===&lt;br /&gt;
You can treat this resource as a [http://en.wikipedia.org/wiki/Common_Gateway_Interface CGI], by writing a second, wrapper, file that refers to it:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;# hello_world.cgi:&lt;br /&gt;
#!/usr/bin/python&lt;br /&gt;
from mulib import cgiadapter&lt;br /&gt;
&lt;br /&gt;
cgiadapter.run_as_cgi(&#039;hello_world&#039;, &#039;HelloWorld&#039;)&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configure your web server to execute hello_world.cgi, and you should be able to interact with it just like the standalone version.&lt;br /&gt;
&lt;br /&gt;
== stacked ==&lt;br /&gt;
&lt;br /&gt;
Stacked is a pure REST server, and you can use it to traverse native python objects like &amp;lt;code&amp;gt;dicts&amp;lt;/code&amp;gt;.  You invoke these special capabilities of Stacked by placing a python dict or list in the resource hierarchy instead of a mu.Resource, in this case at the root.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;python&amp;gt;from mulib import mu&lt;br /&gt;
&lt;br /&gt;
from eventlet import api, httpd&lt;br /&gt;
&lt;br /&gt;
root = {&#039;&#039;:&#039;hello, world\n&#039;,&lt;br /&gt;
        &#039;other&#039;:&amp;quot;hello, other\n&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
httpd.server(api.tcp_listener((&#039;0.0.0.0&#039;, 8080)), mu.SiteMap(root))&amp;lt;/python&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can then access this dictionary as a REST resource, e.g.&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
 &amp;gt; curl http://localhost:8080/     &lt;br /&gt;
 hello, world&lt;br /&gt;
 &amp;gt; curl http://localhost:8080/other&lt;br /&gt;
 hello, other&lt;br /&gt;
 &amp;gt; curl -X PUT -d &amp;quot;the new data&amp;quot; http://localhost:8080/third&lt;br /&gt;
 &amp;gt; curl http://localhost:8080/third&lt;br /&gt;
 the new data&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Mu/stacked can do content negotiation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
 &amp;gt; curl -X PUT -H &amp;quot;Content-type: application/json&amp;quot; -d &#039;{&amp;quot;hi&amp;quot;: &amp;quot;there&amp;quot;}&#039; http://localhost:8080/fourth&lt;br /&gt;
 &amp;gt; curl http://localhost:8080/fourth/hi&lt;br /&gt;
 there&lt;br /&gt;
 &amp;gt; curl -H &amp;quot;Accept: application/json&amp;quot; http://localhost:8080/fourth&lt;br /&gt;
 {&#039;hi&#039;: &#039;there&#039;}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; This means that anyone who has access to your stacked web service can modify the data in your process!  In the future we might have a &#039;read-only&#039; implementation.&lt;br /&gt;
&lt;br /&gt;
== Chat Server ==&lt;br /&gt;
[http://www.evilchuck.com/ EvilChuck] wrote a nifty [http://www.evilchuck.com/2008/02/toy-chat-server-with-eventlet-and-mulib.html toy chat server].&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Library_Call_Test_2&amp;diff=52678</id>
		<title>LSL Library Call Test 2</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Library_Call_Test_2&amp;diff=52678"/>
		<updated>2008-02-05T01:04:37Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Conformance Test]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Tests that LSL library functions are callable and that parameter and return types are correct&lt;br /&gt;
* Does NOT test library call semantics&lt;br /&gt;
* To run, rez a prim, add this script, then touch the prim&lt;br /&gt;
* On successful completion says &amp;quot;Ran 172 tests in 50 seconds&amp;quot;&lt;br /&gt;
* Test should take ~50s due to sleep and energy delays&lt;br /&gt;
* Generates multiple script errors due to erroneous parameters, these errors should be ignored&lt;br /&gt;
* For more verbose reporting uncomment llSay call in test()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
integer gTests = 0;&lt;br /&gt;
&lt;br /&gt;
test(string name)&lt;br /&gt;
{&lt;br /&gt;
    ++gTests;&lt;br /&gt;
    //llSay(0, name);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tests()&lt;br /&gt;
{&lt;br /&gt;
    float floatResult;&lt;br /&gt;
    integer integerResult;&lt;br /&gt;
    string stringResult;&lt;br /&gt;
    key keyResult;&lt;br /&gt;
    vector vectorResult;&lt;br /&gt;
    rotation rotationResult;&lt;br /&gt;
    list listResult;&lt;br /&gt;
    &lt;br /&gt;
    test(&amp;quot;llGetInventoryKey&amp;quot;); keyResult = llGetInventoryKey(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llAllowInventoryDrop&amp;quot;); llAllowInventoryDrop(42);&lt;br /&gt;
    test(&amp;quot;llGetSunDirection&amp;quot;); vectorResult = llGetSunDirection();&lt;br /&gt;
    test(&amp;quot;llGetTextureOffset&amp;quot;); vectorResult = llGetTextureOffset(42);&lt;br /&gt;
    test(&amp;quot;llGetTextureScale&amp;quot;); vectorResult = llGetTextureScale(42);&lt;br /&gt;
    test(&amp;quot;llGetTextureRot&amp;quot;); floatResult = llGetTextureRot(42);&lt;br /&gt;
    test(&amp;quot;llSubStringIndex&amp;quot;); integerResult = llSubStringIndex(&amp;quot;foo&amp;quot;, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetOwnerKey&amp;quot;); keyResult = llGetOwnerKey(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llGetCenterOfMass&amp;quot;); vectorResult = llGetCenterOfMass();&lt;br /&gt;
    test(&amp;quot;llGetListLength&amp;quot;); integerResult = llGetListLength([3]);&lt;br /&gt;
    test(&amp;quot;llList2Integer&amp;quot;); integerResult = llList2Integer([3], 42);&lt;br /&gt;
    test(&amp;quot;llList2Float&amp;quot;); floatResult = llList2Float([3], 42);&lt;br /&gt;
    test(&amp;quot;llList2String&amp;quot;); stringResult = llList2String([3], 42);&lt;br /&gt;
    test(&amp;quot;llList2Key&amp;quot;); keyResult = llList2Key([3], 42);&lt;br /&gt;
    test(&amp;quot;llList2Vector&amp;quot;); vectorResult = llList2Vector([3], 42);&lt;br /&gt;
    test(&amp;quot;llList2Rot&amp;quot;); rotationResult = llList2Rot([3], 42);&lt;br /&gt;
    test(&amp;quot;llCSV2List&amp;quot;); listResult = llCSV2List(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetRegionCorner&amp;quot;); vectorResult = llGetRegionCorner();&lt;br /&gt;
    test(&amp;quot;llGetObjectName&amp;quot;); stringResult = llGetObjectName();&lt;br /&gt;
    test(&amp;quot;llSetObjectName&amp;quot;); llSetObjectName(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetDate&amp;quot;); stringResult = llGetDate();&lt;br /&gt;
    test(&amp;quot;llEdgeOfWorld&amp;quot;); integerResult = llEdgeOfWorld(&amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llGetAgentInfo&amp;quot;); integerResult = llGetAgentInfo(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llAdjustSoundVolume&amp;quot;); llAdjustSoundVolume(0.5);&lt;br /&gt;
    test(&amp;quot;llSetSoundQueueing&amp;quot;); llSetSoundQueueing(42);&lt;br /&gt;
    test(&amp;quot;llSetSoundRadius&amp;quot;); llSetSoundRadius(0.5);&lt;br /&gt;
    test(&amp;quot;llKey2Name&amp;quot;); stringResult = llKey2Name(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llSetTextureAnim&amp;quot;); llSetTextureAnim(42, 42, 42, 42, 0.5, 0.5, 0.5);&lt;br /&gt;
    test(&amp;quot;llTriggerSoundLimited&amp;quot;); llTriggerSoundLimited(&amp;quot;foo&amp;quot;, 0.5, &amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llEjectFromLand&amp;quot;); llEjectFromLand(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llOverMyLand&amp;quot;); integerResult = llOverMyLand(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llGetLandOwnerAt&amp;quot;); keyResult = llGetLandOwnerAt(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llGetNotecardLine&amp;quot;); keyResult = llGetNotecardLine(&amp;quot;foo&amp;quot;, 42);&lt;br /&gt;
    test(&amp;quot;llGetAgentSize&amp;quot;); vectorResult = llGetAgentSize(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llSameGroup&amp;quot;); integerResult = llSameGroup(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llUnSit&amp;quot;); llUnSit(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llGroundSlope&amp;quot;); vectorResult = llGroundSlope(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llGroundNormal&amp;quot;); vectorResult = llGroundNormal(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llGroundContour&amp;quot;); vectorResult = llGroundContour(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llGetAttached&amp;quot;); integerResult = llGetAttached();&lt;br /&gt;
    test(&amp;quot;llGetFreeMemory&amp;quot;); integerResult = llGetFreeMemory();&lt;br /&gt;
    test(&amp;quot;llGetRegionName&amp;quot;); stringResult = llGetRegionName();&lt;br /&gt;
    test(&amp;quot;llGetRegionTimeDilation&amp;quot;); floatResult = llGetRegionTimeDilation();&lt;br /&gt;
    test(&amp;quot;llGetRegionFPS&amp;quot;); floatResult = llGetRegionFPS();&lt;br /&gt;
    test(&amp;quot;llGroundRepel&amp;quot;); llGroundRepel(0.5, 42, 0.5);&lt;br /&gt;
    test(&amp;quot;llScriptDanger&amp;quot;); integerResult = llScriptDanger(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llSetVehicleType&amp;quot;); llSetVehicleType(42);&lt;br /&gt;
    test(&amp;quot;llSetVehicleFloatParam&amp;quot;); llSetVehicleFloatParam(42, 0.5);&lt;br /&gt;
    test(&amp;quot;llSetVehicleVectorParam&amp;quot;); llSetVehicleVectorParam(42, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llSetVehicleRotationParam&amp;quot;); llSetVehicleRotationParam(42, &amp;lt;1.1,2.2,3.3,4.4&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llSetVehicleFlags&amp;quot;); llSetVehicleFlags(42);&lt;br /&gt;
    test(&amp;quot;llRemoveVehicleFlags&amp;quot;); llRemoveVehicleFlags(42);&lt;br /&gt;
    test(&amp;quot;llSitTarget&amp;quot;); llSitTarget(&amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3,4.4&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llAvatarOnSitTarget&amp;quot;); keyResult = llAvatarOnSitTarget();&lt;br /&gt;
    test(&amp;quot;llAddToLandPassList&amp;quot;); llAddToLandPassList(NULL_KEY, 0.5);&lt;br /&gt;
    test(&amp;quot;llSetTouchText&amp;quot;); llSetTouchText(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llSetSitText&amp;quot;); llSetSitText(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llSetCameraEyeOffset&amp;quot;); llSetCameraEyeOffset(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llSetCameraAtOffset&amp;quot;); llSetCameraAtOffset(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llVolumeDetect&amp;quot;); llVolumeDetect(42);&lt;br /&gt;
    test(&amp;quot;llResetOtherScript&amp;quot;); llResetOtherScript(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetScriptState&amp;quot;); integerResult = llGetScriptState(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llRemoteLoadScript&amp;quot;); llRemoteLoadScript(NULL_KEY, &amp;quot;foo&amp;quot;, 42, 42);&lt;br /&gt;
    test(&amp;quot;llOpenRemoteDataChannel&amp;quot;); llOpenRemoteDataChannel();&lt;br /&gt;
    test(&amp;quot;llSendRemoteData&amp;quot;); keyResult = llSendRemoteData(NULL_KEY, &amp;quot;foo&amp;quot;, 42, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llRemoteDataReply&amp;quot;); llRemoteDataReply(NULL_KEY, NULL_KEY, &amp;quot;foo&amp;quot;, 42);&lt;br /&gt;
    test(&amp;quot;llCloseRemoteDataChannel&amp;quot;); llCloseRemoteDataChannel(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llMD5String&amp;quot;); stringResult = llMD5String(&amp;quot;foo&amp;quot;, 42);&lt;br /&gt;
    test(&amp;quot;llStringToBase64&amp;quot;); stringResult = llStringToBase64(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llBase64ToString&amp;quot;); stringResult = llBase64ToString(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llXorBase64Strings&amp;quot;); stringResult = llXorBase64Strings(&amp;quot;foo&amp;quot;, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llSetRemoteScriptAccessPin&amp;quot;); llSetRemoteScriptAccessPin(42);&lt;br /&gt;
    test(&amp;quot;llRemoteLoadScriptPin&amp;quot;); llRemoteLoadScriptPin(NULL_KEY, &amp;quot;foo&amp;quot;, 42, 42, 42);&lt;br /&gt;
    test(&amp;quot;llRemoteDataSetRegion&amp;quot;); llRemoteDataSetRegion();&lt;br /&gt;
    test(&amp;quot;llLog10&amp;quot;); floatResult = llLog10(0.5);&lt;br /&gt;
    test(&amp;quot;llLog&amp;quot;); floatResult = llLog(0.5);&lt;br /&gt;
    test(&amp;quot;llSetParcelMusicURL&amp;quot;); llSetParcelMusicURL(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetRootPosition&amp;quot;); vectorResult = llGetRootPosition();&lt;br /&gt;
    test(&amp;quot;llGetRootRotation&amp;quot;); rotationResult = llGetRootRotation();&lt;br /&gt;
    test(&amp;quot;llGetObjectDesc&amp;quot;); stringResult = llGetObjectDesc();&lt;br /&gt;
    test(&amp;quot;llSetObjectDesc&amp;quot;); llSetObjectDesc(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetCreator&amp;quot;); keyResult = llGetCreator();&lt;br /&gt;
    test(&amp;quot;llGetTimestamp&amp;quot;); stringResult = llGetTimestamp();&lt;br /&gt;
    test(&amp;quot;llSetLinkAlpha&amp;quot;); llSetLinkAlpha(42, 0.5, 42);&lt;br /&gt;
    test(&amp;quot;llGetNumberOfPrims&amp;quot;); integerResult = llGetNumberOfPrims();&lt;br /&gt;
    test(&amp;quot;llGetNumberOfNotecardLines&amp;quot;); keyResult = llGetNumberOfNotecardLines(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetBoundingBox&amp;quot;); listResult = llGetBoundingBox(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llGetGeometricCenter&amp;quot;); vectorResult = llGetGeometricCenter();&lt;br /&gt;
    test(&amp;quot;llIntegerToBase64&amp;quot;); stringResult = llIntegerToBase64(42);&lt;br /&gt;
    test(&amp;quot;llBase64ToInteger&amp;quot;); integerResult = llBase64ToInteger(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetGMTclock&amp;quot;); floatResult = llGetGMTclock();&lt;br /&gt;
    test(&amp;quot;llGetSimulatorHostname&amp;quot;); stringResult = llGetSimulatorHostname();&lt;br /&gt;
    test(&amp;quot;llSetLocalRot&amp;quot;); llSetLocalRot(&amp;lt;1.1,2.2,3.3,4.4&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llRezAtRoot&amp;quot;); llRezAtRoot(&amp;quot;foo&amp;quot;, &amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3,4.4&amp;gt;, 42);&lt;br /&gt;
    test(&amp;quot;llGetObjectPermMask&amp;quot;); integerResult = llGetObjectPermMask(42);&lt;br /&gt;
    //test(&amp;quot;llSetObjectPermMask&amp;quot;); llSetObjectPermMask(42,42);&lt;br /&gt;
    test(&amp;quot;llGetInventoryPermMask&amp;quot;); integerResult = llGetInventoryPermMask(&amp;quot;foo&amp;quot;, 42);&lt;br /&gt;
    //test(&amp;quot;llSetInventoryPermMask&amp;quot;); llSetInventoryPermMask(&amp;quot;foo&amp;quot;, 42, 42);&lt;br /&gt;
    test(&amp;quot;llOwnerSay&amp;quot;); llOwnerSay(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetInventoryCreator&amp;quot;); keyResult = llGetInventoryCreator(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llRequestSimulatorData&amp;quot;); keyResult = llRequestSimulatorData(&amp;quot;foo&amp;quot;, 42);&lt;br /&gt;
    test(&amp;quot;llForceMouselook&amp;quot;); llForceMouselook(42);&lt;br /&gt;
    test(&amp;quot;llGetObjectMass&amp;quot;); floatResult = llGetObjectMass(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llLoadURL&amp;quot;); llLoadURL(NULL_KEY, &amp;quot;foo&amp;quot;, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llModPow&amp;quot;); integerResult = llModPow(42, 42, 42);&lt;br /&gt;
    test(&amp;quot;llGetInventoryType&amp;quot;); integerResult = llGetInventoryType(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetCameraPos&amp;quot;); vectorResult = llGetCameraPos();&lt;br /&gt;
    test(&amp;quot;llGetCameraRot&amp;quot;); rotationResult = llGetCameraRot();&lt;br /&gt;
    test(&amp;quot;llSetPrimURL&amp;quot;); llSetPrimURL(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llRefreshPrimURL&amp;quot;); llRefreshPrimURL();&lt;br /&gt;
    test(&amp;quot;llEscapeURL&amp;quot;); stringResult = llEscapeURL(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llUnescapeURL&amp;quot;); stringResult = llUnescapeURL(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llMapDestination&amp;quot;); llMapDestination(&amp;quot;foo&amp;quot;, &amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llAddToLandBanList&amp;quot;); llAddToLandBanList(NULL_KEY, 0.5);&lt;br /&gt;
    test(&amp;quot;llRemoveFromLandPassList&amp;quot;); llRemoveFromLandPassList(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llRemoveFromLandBanList&amp;quot;); llRemoveFromLandBanList(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llResetLandBanList&amp;quot;); llResetLandBanList();&lt;br /&gt;
    test(&amp;quot;llResetLandPassList&amp;quot;); llResetLandPassList();&lt;br /&gt;
    test(&amp;quot;llClearCameraParams&amp;quot;); llClearCameraParams();&lt;br /&gt;
    test(&amp;quot;llGetUnixTime&amp;quot;); integerResult = llGetUnixTime();&lt;br /&gt;
    test(&amp;quot;llGetParcelFlags&amp;quot;); integerResult = llGetParcelFlags(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llGetRegionFlags&amp;quot;); integerResult = llGetRegionFlags();&lt;br /&gt;
    test(&amp;quot;llGetObjectPrimCount&amp;quot;); integerResult = llGetObjectPrimCount(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llGetParcelPrimOwners&amp;quot;); listResult = llGetParcelPrimOwners(&amp;lt;1.1,2.2,3.3&amp;gt;); &lt;br /&gt;
    test(&amp;quot;llGetParcelPrimCount&amp;quot;); integerResult = llGetParcelPrimCount(&amp;lt;1.1,2.2,3.3&amp;gt;, 42, 42);&lt;br /&gt;
    test(&amp;quot;llGetParcelMaxPrims&amp;quot;); integerResult = llGetParcelMaxPrims(&amp;lt;1.1,2.2,3.3&amp;gt;, 42);&lt;br /&gt;
    test(&amp;quot;llSetLinkTexture&amp;quot;); llSetLinkTexture(42, &amp;quot;foo&amp;quot;, 42);&lt;br /&gt;
    test(&amp;quot;llStringTrim&amp;quot;); stringResult = llStringTrim(&amp;quot;foo&amp;quot;, 42);&lt;br /&gt;
    test(&amp;quot;llRegionSay&amp;quot;); llRegionSay(42, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llListSort&amp;quot;); listResult = llListSort([3], 42, 42);&lt;br /&gt;
    test(&amp;quot;llList2List&amp;quot;); listResult = llList2List([3], 42, 42);&lt;br /&gt;
    test(&amp;quot;llDeleteSubList&amp;quot;); listResult = llDeleteSubList([3], 42, 42);&lt;br /&gt;
    test(&amp;quot;llGetListEntryType&amp;quot;); integerResult = llGetListEntryType([3], 42);&lt;br /&gt;
    test(&amp;quot;llList2CSV&amp;quot;); stringResult = llList2CSV([3]);&lt;br /&gt;
    test(&amp;quot;llListRandomize&amp;quot;); listResult = llListRandomize([3], 42);&lt;br /&gt;
    test(&amp;quot;llList2ListStrided&amp;quot;); listResult = llList2ListStrided([3], 42, 42, 42);&lt;br /&gt;
    test(&amp;quot;llListInsertList&amp;quot;); listResult = llListInsertList([3], [3], 42);&lt;br /&gt;
    test(&amp;quot;llListFindList&amp;quot;); integerResult = llListFindList([3], [3]);&lt;br /&gt;
    test(&amp;quot;llParseString2List&amp;quot;); listResult = llParseString2List(&amp;quot;foo&amp;quot;, [3], [3]);&lt;br /&gt;
    test(&amp;quot;llParticleSystem&amp;quot;); llParticleSystem([3]);&lt;br /&gt;
    test(&amp;quot;llGiveInventoryList&amp;quot;); llGiveInventoryList(NULL_KEY, &amp;quot;foo&amp;quot;, [3]);&lt;br /&gt;
    test(&amp;quot;llDumpList2String&amp;quot;); stringResult = llDumpList2String([3], &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llDialog&amp;quot;); llDialog(NULL_KEY, &amp;quot;foo&amp;quot;, [3], 42);&lt;br /&gt;
    test(&amp;quot;llSetPrimitiveParams&amp;quot;); llSetPrimitiveParams([3]);&lt;br /&gt;
    test(&amp;quot;llGetPrimitiveParams&amp;quot;); listResult = llGetPrimitiveParams([3]);&lt;br /&gt;
    test(&amp;quot;llParseStringKeepNulls&amp;quot;); listResult = llParseStringKeepNulls(&amp;quot;foo&amp;quot;, [3], [3]);&lt;br /&gt;
    test(&amp;quot;llListReplaceList&amp;quot;); listResult = llListReplaceList([3], [3], 42, 42);&lt;br /&gt;
    test(&amp;quot;llParcelMediaCommandList&amp;quot;); llParcelMediaCommandList([3]);&lt;br /&gt;
    test(&amp;quot;llParcelMediaQuery&amp;quot;); listResult = llParcelMediaQuery([3]);&lt;br /&gt;
    test(&amp;quot;llSetPayPrice&amp;quot;); llSetPayPrice(42, [3]);&lt;br /&gt;
    test(&amp;quot;llSetCameraParams&amp;quot;); llSetCameraParams([3]);&lt;br /&gt;
    test(&amp;quot;llListStatistics&amp;quot;); floatResult = llListStatistics(42, [3]);&lt;br /&gt;
    test(&amp;quot;llGetParcelDetails&amp;quot;); listResult = llGetParcelDetails(&amp;lt;1.1,2.2,3.3&amp;gt;, [3]);&lt;br /&gt;
    test(&amp;quot;llSetLinkPrimitiveParams&amp;quot;); llSetLinkPrimitiveParams(42, [3]);&lt;br /&gt;
    //test(&amp;quot;llGetObjectDetails&amp;quot;); listResult = llGetObjectDetails(NULL_KEY, [3]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    touch_start(integer total_number)&lt;br /&gt;
    {&lt;br /&gt;
        llResetTime();&lt;br /&gt;
        tests();&lt;br /&gt;
        llSay(0, &amp;quot;Ran &amp;quot; + (string) gTests + &amp;quot; tests in &amp;quot; + (string) llGetTime() + &amp;quot; seconds&amp;quot;);&lt;br /&gt;
        gTests = 0;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Library_Call_Test_1&amp;diff=52677</id>
		<title>LSL Library Call Test 1</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Library_Call_Test_1&amp;diff=52677"/>
		<updated>2008-02-05T01:03:59Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Conformance Test]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Tests that LSL library functions are callable and that parameter and return types are correct&lt;br /&gt;
* Does NOT test library call semantics&lt;br /&gt;
* To run, rez a prim, add this script, then touch the prim&lt;br /&gt;
* On successful completion says &amp;quot;Ran 172 tests in 50 seconds&amp;quot;&lt;br /&gt;
* Test should take ~50s due to sleep and energy delays&lt;br /&gt;
* Generates multiple script errors due to erroneous parameters, these errors should be ignored&lt;br /&gt;
* For more verbose reporting uncomment llSay call in test()&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
integer gTests = 0;&lt;br /&gt;
&lt;br /&gt;
test(string name)&lt;br /&gt;
{&lt;br /&gt;
    ++gTests;&lt;br /&gt;
    //llSay(0, name);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tests()&lt;br /&gt;
{&lt;br /&gt;
    float floatResult;&lt;br /&gt;
    integer integerResult;&lt;br /&gt;
    string stringResult;&lt;br /&gt;
    key keyResult;&lt;br /&gt;
    vector vectorResult;&lt;br /&gt;
    rotation rotationResult;&lt;br /&gt;
    list listResult;&lt;br /&gt;
        &lt;br /&gt;
    test(&amp;quot;llSin&amp;quot;); floatResult = llSin(0.5);&lt;br /&gt;
    test(&amp;quot;llCos&amp;quot;); floatResult = llCos(0.5);&lt;br /&gt;
    test(&amp;quot;llTan&amp;quot;); floatResult = llTan(0.5);&lt;br /&gt;
    test(&amp;quot;llAtan2&amp;quot;); floatResult = llAtan2(0.5, 0.5);&lt;br /&gt;
    test(&amp;quot;llSqrt&amp;quot;); floatResult = llSqrt(0.5);&lt;br /&gt;
    test(&amp;quot;llPow&amp;quot;); floatResult = llPow(0.5, 0.5);&lt;br /&gt;
    test(&amp;quot;llAbs&amp;quot;); integerResult = llAbs(42);&lt;br /&gt;
    test(&amp;quot;llFabs&amp;quot;); floatResult = llFabs(0.5);&lt;br /&gt;
    test(&amp;quot;llFrand&amp;quot;); floatResult = llFrand(0.5);&lt;br /&gt;
    test(&amp;quot;llFloor&amp;quot;); integerResult = llFloor(0.5);&lt;br /&gt;
    test(&amp;quot;llCeil&amp;quot;); integerResult = llCeil(0.5);&lt;br /&gt;
    test(&amp;quot;llRound&amp;quot;); integerResult = llRound(0.5);&lt;br /&gt;
    test(&amp;quot;llVecMag&amp;quot;); floatResult = llVecMag(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llVecNorm&amp;quot;); vectorResult = llVecNorm(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llVecDist&amp;quot;); floatResult = llVecDist(&amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llRot2Euler&amp;quot;); vectorResult = llRot2Euler(&amp;lt;1.1,2.2,3.3,4.4&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llEuler2Rot&amp;quot;); rotationResult = llEuler2Rot(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llAxes2Rot&amp;quot;); rotationResult = llAxes2Rot(&amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llRot2Fwd&amp;quot;); vectorResult = llRot2Fwd(&amp;lt;1.1,2.2,3.3,4.4&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llRot2Left&amp;quot;); vectorResult = llRot2Left(&amp;lt;1.1,2.2,3.3,4.4&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llRot2Up&amp;quot;); vectorResult = llRot2Up(&amp;lt;1.1,2.2,3.3,4.4&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llRotBetween&amp;quot;); rotationResult = llRotBetween(&amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llWhisper&amp;quot;); llWhisper(42, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llSay&amp;quot;); llSay(42, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llShout&amp;quot;); llShout(42, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llListen&amp;quot;); integerResult = llListen(42, &amp;quot;foo&amp;quot;, NULL_KEY, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llListenControl&amp;quot;); llListenControl(42, 42);&lt;br /&gt;
    test(&amp;quot;llListenRemove&amp;quot;); llListenRemove(42);&lt;br /&gt;
    test(&amp;quot;llSensor&amp;quot;); llSensor(&amp;quot;foo&amp;quot;, NULL_KEY, 42, 0.5, 0.5);&lt;br /&gt;
    test(&amp;quot;llSensorRepeat&amp;quot;); llSensorRepeat(&amp;quot;foo&amp;quot;, NULL_KEY, 42, 0.5, 0.5, 0.5);&lt;br /&gt;
    test(&amp;quot;llSensorRemove&amp;quot;); llSensorRemove();&lt;br /&gt;
    test(&amp;quot;llDetectedName&amp;quot;); stringResult = llDetectedName(42);&lt;br /&gt;
    test(&amp;quot;llDetectedKey&amp;quot;); keyResult = llDetectedKey(42);&lt;br /&gt;
    test(&amp;quot;llDetectedOwner&amp;quot;); keyResult = llDetectedOwner(42);&lt;br /&gt;
    test(&amp;quot;llDetectedType&amp;quot;); integerResult = llDetectedType(42);&lt;br /&gt;
    test(&amp;quot;llDetectedPos&amp;quot;); vectorResult = llDetectedPos(42);&lt;br /&gt;
    test(&amp;quot;llDetectedVel&amp;quot;); vectorResult = llDetectedVel(42);&lt;br /&gt;
    test(&amp;quot;llDetectedGrab&amp;quot;); vectorResult = llDetectedGrab(42);&lt;br /&gt;
    test(&amp;quot;llDetectedRot&amp;quot;); rotationResult = llDetectedRot(42);&lt;br /&gt;
    test(&amp;quot;llDetectedGroup&amp;quot;); integerResult = llDetectedGroup(42);&lt;br /&gt;
    test(&amp;quot;llDetectedLinkNumber&amp;quot;); integerResult = llDetectedLinkNumber(42);&lt;br /&gt;
    test(&amp;quot;llDie&amp;quot;); //llDie();&lt;br /&gt;
    test(&amp;quot;llGround&amp;quot;); floatResult = llGround(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llCloud&amp;quot;); floatResult = llCloud(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llWind&amp;quot;); vectorResult = llWind(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llSetStatus&amp;quot;); llSetStatus(42, 42);&lt;br /&gt;
    test(&amp;quot;llGetStatus&amp;quot;); integerResult = llGetStatus(42);&lt;br /&gt;
    test(&amp;quot;llSetScale&amp;quot;); llSetScale(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llGetScale&amp;quot;); vectorResult = llGetScale();&lt;br /&gt;
    test(&amp;quot;llSetColor&amp;quot;); llSetColor(&amp;lt;1.1,2.2,3.3&amp;gt;, 42);&lt;br /&gt;
    test(&amp;quot;llGetColor&amp;quot;); vectorResult = llGetColor(0);&lt;br /&gt;
    test(&amp;quot;llSetAlpha&amp;quot;); llSetAlpha(0.5, 42);&lt;br /&gt;
    test(&amp;quot;llGetAlpha&amp;quot;); floatResult = llGetAlpha(42);&lt;br /&gt;
    test(&amp;quot;llSetTexture&amp;quot;); llSetTexture(&amp;quot;foo&amp;quot;, 42);&lt;br /&gt;
    test(&amp;quot;llScaleTexture&amp;quot;); llScaleTexture(0.5, 0.5, 42);&lt;br /&gt;
    test(&amp;quot;llOffsetTexture&amp;quot;); llOffsetTexture(0.5, 0.5, 42);&lt;br /&gt;
    test(&amp;quot;llRotateTexture&amp;quot;); llRotateTexture(0.5, 42);&lt;br /&gt;
    test(&amp;quot;llGetTexture&amp;quot;); stringResult = llGetTexture(42);&lt;br /&gt;
    test(&amp;quot;llSetPos&amp;quot;); //llSetPos(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llGetPos&amp;quot;); vectorResult = llGetPos();&lt;br /&gt;
    test(&amp;quot;llGetLocalPos&amp;quot;); vectorResult = llGetLocalPos();&lt;br /&gt;
    test(&amp;quot;llSetRot&amp;quot;); llSetRot(&amp;lt;1.1,2.2,3.3,4.4&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llGetRot&amp;quot;); rotationResult = llGetRot();&lt;br /&gt;
    test(&amp;quot;llGetLocalRot&amp;quot;); rotationResult = llGetLocalRot();&lt;br /&gt;
    test(&amp;quot;llSetForce&amp;quot;); llSetForce(&amp;lt;1.1,2.2,3.3&amp;gt;, 42);&lt;br /&gt;
    test(&amp;quot;llGetForce&amp;quot;); vectorResult = llGetForce();&lt;br /&gt;
    test(&amp;quot;llMoveToTarget&amp;quot;); llMoveToTarget(&amp;lt;1.1,2.2,3.3&amp;gt;, 0.5);&lt;br /&gt;
    test(&amp;quot;llStopMoveToTarget&amp;quot;); llStopMoveToTarget();&lt;br /&gt;
    test(&amp;quot;llTarget&amp;quot;); integerResult = llTarget(&amp;lt;1.1,2.2,3.3&amp;gt;, 0.5);&lt;br /&gt;
    test(&amp;quot;llTargetRemove&amp;quot;); llTargetRemove(42);&lt;br /&gt;
    test(&amp;quot;llRotTarget&amp;quot;); integerResult = llRotTarget(&amp;lt;1.1,2.2,3.3,4.4&amp;gt;, 0.5);&lt;br /&gt;
    test(&amp;quot;llRotTargetRemove&amp;quot;); llRotTargetRemove(42);&lt;br /&gt;
    test(&amp;quot;llApplyImpulse&amp;quot;); llApplyImpulse(&amp;lt;1.1,2.2,3.3&amp;gt;, 42);&lt;br /&gt;
    test(&amp;quot;llApplyRotationalImpulse&amp;quot;); llApplyRotationalImpulse(&amp;lt;1.1,2.2,3.3&amp;gt;, 42);&lt;br /&gt;
    test(&amp;quot;llSetTorque&amp;quot;); llSetTorque(&amp;lt;1.1,2.2,3.3&amp;gt;, 42);&lt;br /&gt;
    test(&amp;quot;llGetTorque&amp;quot;); vectorResult = llGetTorque();&lt;br /&gt;
    test(&amp;quot;llSetForceAndTorque&amp;quot;); llSetForceAndTorque(&amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3&amp;gt;, 42);&lt;br /&gt;
    test(&amp;quot;llGetVel&amp;quot;); vectorResult = llGetVel();&lt;br /&gt;
    test(&amp;quot;llGetAccel&amp;quot;); vectorResult = llGetAccel();&lt;br /&gt;
    test(&amp;quot;llGetOmega&amp;quot;); vectorResult = llGetOmega();&lt;br /&gt;
    test(&amp;quot;llGetTimeOfDay&amp;quot;); floatResult = llGetTimeOfDay();&lt;br /&gt;
    test(&amp;quot;llGetWallclock&amp;quot;); floatResult = llGetWallclock();&lt;br /&gt;
    test(&amp;quot;llGetTime&amp;quot;); floatResult = llGetTime();&lt;br /&gt;
    test(&amp;quot;llResetTime&amp;quot;); //llResetTime();&lt;br /&gt;
    test(&amp;quot;llGetAndResetTime&amp;quot;); //floatResult = llGetAndResetTime();&lt;br /&gt;
    test(&amp;quot;llSound&amp;quot;); llSound(&amp;quot;foo&amp;quot;, 0.5, 42, 42);&lt;br /&gt;
    test(&amp;quot;llPlaySound&amp;quot;); llPlaySound(NULL_KEY, 0.5);&lt;br /&gt;
    test(&amp;quot;llLoopSound&amp;quot;); llLoopSound(&amp;quot;foo&amp;quot;, 0.5);&lt;br /&gt;
    test(&amp;quot;llLoopSoundMaster&amp;quot;); llLoopSoundMaster(&amp;quot;foo&amp;quot;, 0.5);&lt;br /&gt;
    test(&amp;quot;llLoopSoundSlave&amp;quot;); llLoopSoundSlave(&amp;quot;foo&amp;quot;, 0.5);&lt;br /&gt;
    test(&amp;quot;llPlaySoundSlave&amp;quot;); llPlaySoundSlave(&amp;quot;foo&amp;quot;, 0.5);&lt;br /&gt;
    test(&amp;quot;llTriggerSound&amp;quot;); llTriggerSound(NULL_KEY, 0.5);&lt;br /&gt;
    test(&amp;quot;llStopSound&amp;quot;); llStopSound();&lt;br /&gt;
    test(&amp;quot;llPreloadSound&amp;quot;); llPreloadSound(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetSubString&amp;quot;); stringResult = llGetSubString(&amp;quot;foo&amp;quot;, 42, 42);&lt;br /&gt;
    test(&amp;quot;llDeleteSubString&amp;quot;); stringResult = llDeleteSubString(&amp;quot;foo&amp;quot;, 42, 42);&lt;br /&gt;
    test(&amp;quot;llInsertString&amp;quot;); stringResult = llInsertString(&amp;quot;foo&amp;quot;, 42, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llToUpper&amp;quot;); stringResult = llToUpper(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llToLower&amp;quot;); stringResult = llToLower(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGiveMoney&amp;quot;); integerResult = llGiveMoney(NULL_KEY, 42);&lt;br /&gt;
    //test(&amp;quot;llMakeExplosion&amp;quot;); llMakeExplosion(42, 0.5, 0.5, 0.5, 0.5, &amp;quot;foo&amp;quot;, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    //test(&amp;quot;llMakeFountain&amp;quot;); llMakeFountain(42, 0.5, 0.5, 0.5, 0.5, &amp;quot;foo&amp;quot;, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llMakeSmoke&amp;quot;); llMakeSmoke(42, 0.5, 0.5, 0.5, 0.5, &amp;quot;foo&amp;quot;, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llMakeFire&amp;quot;); llMakeFire(42, 0.5, 0.5, 0.5, 0.5, &amp;quot;foo&amp;quot;, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llRezObject&amp;quot;); llRezObject(&amp;quot;foo&amp;quot;, &amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3,4.4&amp;gt;, 42);&lt;br /&gt;
    test(&amp;quot;llLookAt&amp;quot;); llLookAt(&amp;lt;1.1,2.2,3.3&amp;gt;, 0.5, 0.5);&lt;br /&gt;
    test(&amp;quot;llStopLookAt&amp;quot;); llStopLookAt();&lt;br /&gt;
    test(&amp;quot;llSetTimerEvent&amp;quot;); llSetTimerEvent(0.5);&lt;br /&gt;
    test(&amp;quot;llSleep&amp;quot;); llSleep(0.5);&lt;br /&gt;
    test(&amp;quot;llGetMass&amp;quot;); floatResult = llGetMass();&lt;br /&gt;
    test(&amp;quot;llCollisionFilter&amp;quot;); llCollisionFilter(&amp;quot;foo&amp;quot;, NULL_KEY, 42);&lt;br /&gt;
    test(&amp;quot;llTakeControls&amp;quot;); llTakeControls(42, 42, 42);&lt;br /&gt;
    test(&amp;quot;llReleaseControls&amp;quot;); llReleaseControls();&lt;br /&gt;
    test(&amp;quot;llAttachToAvatar&amp;quot;); llAttachToAvatar(42);&lt;br /&gt;
    test(&amp;quot;llDetachFromAvatar&amp;quot;); llDetachFromAvatar();&lt;br /&gt;
    test(&amp;quot;llGetOwner&amp;quot;); keyResult = llGetOwner();&lt;br /&gt;
    test(&amp;quot;llInstantMessage&amp;quot;); llInstantMessage(NULL_KEY, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llEmail&amp;quot;); llEmail(&amp;quot;foo&amp;quot;, &amp;quot;foo&amp;quot;, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetNextEmail&amp;quot;); llGetNextEmail(&amp;quot;foo&amp;quot;, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetKey&amp;quot;); keyResult = llGetKey();&lt;br /&gt;
    test(&amp;quot;llSetBuoyancy&amp;quot;); llSetBuoyancy(0.5);&lt;br /&gt;
    test(&amp;quot;llSetHoverHeight&amp;quot;); llSetHoverHeight(0.5, 42, 0.5);&lt;br /&gt;
    test(&amp;quot;llStopHover&amp;quot;); llStopHover();&lt;br /&gt;
    test(&amp;quot;llMinEventDelay&amp;quot;); llMinEventDelay(0.5);&lt;br /&gt;
    test(&amp;quot;llSoundPreload&amp;quot;); llSoundPreload(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llRotLookAt&amp;quot;); llRotLookAt(&amp;lt;1.1,2.2,3.3,4.4&amp;gt;, 0.5, 0.5);&lt;br /&gt;
    test(&amp;quot;llStringLength&amp;quot;); integerResult = llStringLength(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llStartAnimation&amp;quot;); llStartAnimation(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llStopAnimation&amp;quot;); llStopAnimation(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llPointAt&amp;quot;); llPointAt(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llStopPointAt&amp;quot;); llStopPointAt();&lt;br /&gt;
    test(&amp;quot;llTargetOmega&amp;quot;); llTargetOmega(&amp;lt;1.1,2.2,3.3&amp;gt;, 0.5, 0.5);&lt;br /&gt;
    test(&amp;quot;llGetStartParameter&amp;quot;); integerResult = llGetStartParameter();&lt;br /&gt;
    //test(&amp;quot;llGodLikeRezObject&amp;quot;); llGodLikeRezObject(NULL_KEY, &amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llRequestPermissions&amp;quot;); llRequestPermissions(NULL_KEY, 42);&lt;br /&gt;
    test(&amp;quot;llGetPermissionsKey&amp;quot;); keyResult = llGetPermissionsKey();&lt;br /&gt;
    test(&amp;quot;llGetPermissions&amp;quot;); integerResult = llGetPermissions();&lt;br /&gt;
    test(&amp;quot;llGetLinkNumber&amp;quot;); integerResult = llGetLinkNumber();&lt;br /&gt;
    test(&amp;quot;llSetLinkColor&amp;quot;); llSetLinkColor(42, &amp;lt;1.1,2.2,3.3&amp;gt;, 42);&lt;br /&gt;
    test(&amp;quot;llCreateLink&amp;quot;); llCreateLink(NULL_KEY, 42);&lt;br /&gt;
    test(&amp;quot;llBreakLink&amp;quot;); llBreakLink(42);&lt;br /&gt;
    test(&amp;quot;llLinks&amp;quot;); llBreakAllLinks();&lt;br /&gt;
    test(&amp;quot;llGetLinkKey&amp;quot;); keyResult = llGetLinkKey(42);&lt;br /&gt;
    test(&amp;quot;llGetLinkName&amp;quot;); stringResult = llGetLinkName(42);&lt;br /&gt;
    test(&amp;quot;llGetInventoryNumber&amp;quot;); integerResult = llGetInventoryNumber(42);&lt;br /&gt;
    test(&amp;quot;llGetInventoryName&amp;quot;); stringResult = llGetInventoryName(42, 42);&lt;br /&gt;
    test(&amp;quot;llSetScriptState&amp;quot;); llSetScriptState(&amp;quot;foo&amp;quot;, 42);&lt;br /&gt;
    test(&amp;quot;llGetEnergy&amp;quot;); floatResult = llGetEnergy();&lt;br /&gt;
    test(&amp;quot;llGiveInventory&amp;quot;); llGiveInventory(NULL_KEY, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llRemoveInventory&amp;quot;); llRemoveInventory(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llSetText&amp;quot;); llSetText(&amp;quot;foo&amp;quot;, &amp;lt;1.1,2.2,3.3&amp;gt;, 0.5);&lt;br /&gt;
    test(&amp;quot;llWater&amp;quot;); floatResult = llWater(&amp;lt;1.1,2.2,3.3&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llPassTouches&amp;quot;); llPassTouches(42);&lt;br /&gt;
    test(&amp;quot;llRequestAgentData&amp;quot;); keyResult = llRequestAgentData(NULL_KEY, 42);&lt;br /&gt;
    test(&amp;quot;llRequestInventoryData&amp;quot;); keyResult = llRequestInventoryData(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llSetDamage&amp;quot;); llSetDamage(0.5);&lt;br /&gt;
    test(&amp;quot;llTeleportAgentHome&amp;quot;); llTeleportAgentHome(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llModifyLand&amp;quot;); llModifyLand(42, 42);&lt;br /&gt;
    test(&amp;quot;llCollisionSound&amp;quot;); llCollisionSound(&amp;quot;foo&amp;quot;, 0.5);&lt;br /&gt;
    test(&amp;quot;llCollisionSprite&amp;quot;); llCollisionSprite(&amp;quot;foo&amp;quot;);&lt;br /&gt;
    test(&amp;quot;llGetAnimation&amp;quot;); stringResult = llGetAnimation(NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llGetAnimationList&amp;quot;); listResult = llGetAnimationList(NULL_KEY);&lt;br /&gt;
    //test(&amp;quot;llResetScript&amp;quot;); llResetScript();&lt;br /&gt;
    test(&amp;quot;llMessageLinked&amp;quot;); llMessageLinked(42, 42, &amp;quot;foo&amp;quot;, NULL_KEY);&lt;br /&gt;
    test(&amp;quot;llPushObject&amp;quot;); llPushObject(NULL_KEY, &amp;lt;1.1,2.2,3.3&amp;gt;, &amp;lt;1.1,2.2,3.3&amp;gt;, 42);&lt;br /&gt;
    test(&amp;quot;llPassCollisions&amp;quot;); llPassCollisions(42);&lt;br /&gt;
    test(&amp;quot;llGetScriptName&amp;quot;); stringResult = llGetScriptName();&lt;br /&gt;
    test(&amp;quot;llGetNumberOfSides&amp;quot;); integerResult = llGetNumberOfSides();&lt;br /&gt;
    test(&amp;quot;llAxisAngle2Rot&amp;quot;); rotationResult = llAxisAngle2Rot(&amp;lt;1.1,2.2,3.3&amp;gt;, 0.5);&lt;br /&gt;
    test(&amp;quot;llRot2Axis&amp;quot;); vectorResult = llRot2Axis(&amp;lt;1.1,2.2,3.3,4.4&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llRot2Angle&amp;quot;); floatResult = llRot2Angle(&amp;lt;1.1,2.2,3.3,4.4&amp;gt;);&lt;br /&gt;
    test(&amp;quot;llAcos&amp;quot;); floatResult = llAcos(0.5);&lt;br /&gt;
    test(&amp;quot;llAsin&amp;quot;); floatResult = llAsin(0.5);&lt;br /&gt;
    test(&amp;quot;llAngleBetween&amp;quot;); floatResult = llAngleBetween(&amp;lt;1.1,2.2,3.3,4.4&amp;gt;, &amp;lt;1.1,2.2,3.3,4.4&amp;gt;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    touch_start(integer total_number)&lt;br /&gt;
    {&lt;br /&gt;
        llResetTime();&lt;br /&gt;
        tests();&lt;br /&gt;
        llSay(0, &amp;quot;Ran &amp;quot; + (string) gTests + &amp;quot; tests in &amp;quot; + (string) llGetTime() + &amp;quot; seconds&amp;quot;);&lt;br /&gt;
        gTests = 0;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Language_Test&amp;diff=52676</id>
		<title>LSL Language Test</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Language_Test&amp;diff=52676"/>
		<updated>2008-02-05T01:02:55Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Conformance Test]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* Tests all LSL language features&lt;br /&gt;
* To run, rez a prim, add this script, then touch the prim&lt;br /&gt;
* On successful completion, says &amp;quot;Ran N tests in X seconds with 0 failures&amp;quot;&lt;br /&gt;
* For more verbose reporting, uncomment llSay call in testPassed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;integer gTestsPassed = 0;&lt;br /&gt;
integer gTestsFailed = 0;&lt;br /&gt;
&lt;br /&gt;
testPassed(string description, string actual, string expected)&lt;br /&gt;
{&lt;br /&gt;
    ++gTestsPassed;&lt;br /&gt;
    //llSay(0, description);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
testFailed(string description, string actual, string expected)&lt;br /&gt;
{&lt;br /&gt;
    ++gTestsFailed;&lt;br /&gt;
    llSay(0, &amp;quot;FAILED!: &amp;quot; + description + &amp;quot; (&amp;quot; + actual + &amp;quot; expected &amp;quot; + expected + &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureTrue(string description, integer actual)&lt;br /&gt;
{&lt;br /&gt;
    if(actual)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) TRUE);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) TRUE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureFalse(string description, integer actual)&lt;br /&gt;
{&lt;br /&gt;
    if(actual)&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) FALSE);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureIntegerEqual(string description, integer actual, integer expected)&lt;br /&gt;
{&lt;br /&gt;
    if(actual == expected)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer floatEqual(float actual, float expected)&lt;br /&gt;
{&lt;br /&gt;
    float error = llFabs(expected - actual);&lt;br /&gt;
    float epsilon = 0.001;&lt;br /&gt;
    if(error &amp;gt; epsilon)&lt;br /&gt;
    {&lt;br /&gt;
        llSay(0,&amp;quot;Float equality delta &amp;quot; + (string)error);&lt;br /&gt;
        return FALSE;&lt;br /&gt;
    }&lt;br /&gt;
    return TRUE;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureFloatEqual(string description, float actual, float expected)&lt;br /&gt;
{&lt;br /&gt;
    if(floatEqual(actual, expected))&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureStringEqual(string description, string actual, string expected)&lt;br /&gt;
{&lt;br /&gt;
    if(actual == expected)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureVectorEqual(string description, vector actual, vector expected)&lt;br /&gt;
{&lt;br /&gt;
    if(floatEqual(actual.x, expected.x) &amp;amp;&amp;amp;&lt;br /&gt;
        floatEqual(actual.y, expected.y) &amp;amp;&amp;amp;&lt;br /&gt;
        floatEqual(actual.z, expected.z))&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureRotationEqual(string description, rotation actual, rotation expected)&lt;br /&gt;
{&lt;br /&gt;
    if(floatEqual(actual.x, expected.x) &amp;amp;&amp;amp;&lt;br /&gt;
        floatEqual(actual.y, expected.y) &amp;amp;&amp;amp;&lt;br /&gt;
        floatEqual(actual.z, expected.z) &amp;amp;&amp;amp;&lt;br /&gt;
        floatEqual(actual.s, expected.s))&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureListEqual(string description, list actual, list expected)&lt;br /&gt;
{&lt;br /&gt;
    if(actual == expected)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer gInteger = 5;&lt;br /&gt;
float gFloat = 1.5;&lt;br /&gt;
string gString = &amp;quot;foo&amp;quot;;&lt;br /&gt;
vector gVector = &amp;lt;1, 2, 3&amp;gt;;&lt;br /&gt;
rotation gRot = &amp;lt;1, 2, 3, 4&amp;gt;;&lt;br /&gt;
list gList = [1, 2, 3];&lt;br /&gt;
&lt;br /&gt;
integer testReturn()&lt;br /&gt;
{&lt;br /&gt;
    return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
float testReturnFloat()&lt;br /&gt;
{&lt;br /&gt;
    return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string testReturnString()&lt;br /&gt;
{&lt;br /&gt;
    return &amp;quot;Test string&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
list testReturnList()&lt;br /&gt;
{&lt;br /&gt;
    return [1,2,3];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
vector testReturnVector()&lt;br /&gt;
{&lt;br /&gt;
    return &amp;lt;1,2,3&amp;gt;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
rotation testReturnRotation()&lt;br /&gt;
{&lt;br /&gt;
    return &amp;lt;1,2,3,4&amp;gt;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
vector testReturnVectorNested()&lt;br /&gt;
{&lt;br /&gt;
    return testReturnVector();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
vector testReturnVectorWithLibraryCall()&lt;br /&gt;
{&lt;br /&gt;
    llSin(0);&lt;br /&gt;
    return &amp;lt;1,2,3&amp;gt;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
rotation testReturnRotationWithLibraryCall()&lt;br /&gt;
{&lt;br /&gt;
    llSin(0);&lt;br /&gt;
    return &amp;lt;1,2,3,4&amp;gt;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer testParameters(integer param)&lt;br /&gt;
{&lt;br /&gt;
    param = param + 1;&lt;br /&gt;
    return param;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer testRecursion(integer param)&lt;br /&gt;
{&lt;br /&gt;
    if(param &amp;lt;= 0)&lt;br /&gt;
    {&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        return testRecursion(param - 1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string testExpressionLists(list l)&lt;br /&gt;
{&lt;br /&gt;
    return &amp;quot;foo&amp;quot; + (string)l;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
tests()&lt;br /&gt;
{&lt;br /&gt;
    // truth&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;TRUE&amp;quot;, TRUE, TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;FALSE&amp;quot;, FALSE, FALSE);&lt;br /&gt;
&lt;br /&gt;
    if(0.0)&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(&amp;quot;if(0.0)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;FALSE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(&amp;quot;if(0.0)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;TRUE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    if(0.000001)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(&amp;quot;if(0.000001)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;TRUE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(&amp;quot;if(0.000001)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;FALSE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    if(0.9)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(&amp;quot;if(0.9)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;TRUE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(&amp;quot;if(0.9)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;FALSE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    if(ZERO_VECTOR)&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(&amp;quot;if(ZERO_VECTOR)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;FALSE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(&amp;quot;if(ZERO_VECTOR)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;TRUE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    if(ZERO_ROTATION)&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(&amp;quot;if(ZERO_ROTATION)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;FALSE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(&amp;quot;if(ZERO_ROTATION)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;TRUE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if(NULL_KEY)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(&amp;quot;if(NULL_KEY)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;TRUE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(&amp;quot;if(NULL_KEY)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;FALSE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    if((key)NULL_KEY)&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(&amp;quot;if((key)NULL_KEY)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;FALSE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(&amp;quot;if((key)NULL_KEY)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;TRUE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    if(&amp;quot;&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(&amp;quot;if(\&amp;quot;\&amp;quot;)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;FALSE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(&amp;quot;if(\&amp;quot;\&amp;quot;)&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;TRUE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if([])&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(&amp;quot;if([])&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;FALSE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(&amp;quot;if([])&amp;quot;, &amp;quot;TRUE&amp;quot;, &amp;quot;TRUE&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // equality&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE == TRUE)&amp;quot;, (TRUE == TRUE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE == FALSE)&amp;quot;, (TRUE == FALSE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE == TRUE)&amp;quot;, (FALSE == TRUE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE == FALSE)&amp;quot;, (FALSE == FALSE), TRUE);&lt;br /&gt;
    &lt;br /&gt;
    // inequality&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE != TRUE)&amp;quot;, (TRUE != TRUE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE != FALSE)&amp;quot;, (TRUE != FALSE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE != TRUE)&amp;quot;, (FALSE != TRUE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE != FALSE)&amp;quot;, (FALSE != FALSE), FALSE);&lt;br /&gt;
    &lt;br /&gt;
    // and&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE &amp;amp;&amp;amp; TRUE)&amp;quot;, (TRUE &amp;amp;&amp;amp; TRUE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE &amp;amp;&amp;amp; FALSE)&amp;quot;, (TRUE &amp;amp;&amp;amp; FALSE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE &amp;amp;&amp;amp; TRUE)&amp;quot;, (FALSE &amp;amp;&amp;amp; TRUE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE &amp;amp;&amp;amp; FALSE)&amp;quot;, (FALSE &amp;amp;&amp;amp; FALSE), FALSE);&lt;br /&gt;
&lt;br /&gt;
    // and&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;amp;&amp;amp; 2)&amp;quot;, (1 &amp;amp;&amp;amp; 2), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;amp;&amp;amp; 0)&amp;quot;, (1 &amp;amp;&amp;amp; 0), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 &amp;amp;&amp;amp; 2)&amp;quot;, (0 &amp;amp;&amp;amp; 2), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 &amp;amp;&amp;amp; 0)&amp;quot;, (0 &amp;amp;&amp;amp; 0), FALSE);&lt;br /&gt;
&lt;br /&gt;
        &lt;br /&gt;
    // or&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE || TRUE)&amp;quot;, (TRUE || TRUE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE || FALSE)&amp;quot;, (TRUE || FALSE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE || TRUE)&amp;quot;, (FALSE || TRUE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE || FALSE)&amp;quot;, (FALSE || FALSE), FALSE);&lt;br /&gt;
    &lt;br /&gt;
    // or&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 || 2)&amp;quot;, (1 || 2), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 || 0)&amp;quot;, (1 || 0), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 || 2)&amp;quot;, (0 || 2), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 || 0)&amp;quot;, (0 || 0), FALSE);&lt;br /&gt;
        &lt;br /&gt;
    // not&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(! TRUE)&amp;quot;, (! TRUE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(! FALSE)&amp;quot;, (! FALSE), TRUE);&lt;br /&gt;
    &lt;br /&gt;
    // not &lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(! 2)&amp;quot;, (! 2), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(! 0)&amp;quot;, (! 0), TRUE);&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    // greater than&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;gt; 0)&amp;quot;, (1 &amp;gt; 0), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 &amp;gt; 1)&amp;quot;, (0 &amp;gt; 1), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;gt; 1)&amp;quot;, (1 &amp;gt; 1), FALSE);&lt;br /&gt;
    &lt;br /&gt;
    // less than&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 &amp;lt; 1)&amp;quot;, (0 &amp;lt; 1), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;lt; 0)&amp;quot;, (1 &amp;lt; 0), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;lt; 1)&amp;quot;, (1 &amp;lt; 1), FALSE);&lt;br /&gt;
    &lt;br /&gt;
    // greater than or equal&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;gt;= 0)&amp;quot;, (1 &amp;gt;= 0), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 &amp;gt;= 1)&amp;quot;, (0 &amp;gt;= 1), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;gt;= 1)&amp;quot;, (1 &amp;gt;= 1), TRUE);&lt;br /&gt;
    &lt;br /&gt;
    // tess than or equal&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 &amp;lt;= 1)&amp;quot;, (0 &amp;lt;= 1), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;lt;= 0)&amp;quot;, (1 &amp;lt;= 0), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;lt;= 1)&amp;quot;, (1 &amp;lt;= 1), TRUE);&lt;br /&gt;
    &lt;br /&gt;
    // bitwise and&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(10 &amp;amp; 25)&amp;quot;, (10 &amp;amp; 25), 8);&lt;br /&gt;
    &lt;br /&gt;
    // bitwise or&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(10 | 25)&amp;quot;, (10 | 25), 27);&lt;br /&gt;
    &lt;br /&gt;
    // bitwise not&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;~10&amp;quot;, ~10, -11);&lt;br /&gt;
    &lt;br /&gt;
    // xor&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(10 ^ 25)&amp;quot;, (10 ^ 25), 19);&lt;br /&gt;
    &lt;br /&gt;
    // right shift&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(523 &amp;gt;&amp;gt; 2)&amp;quot;, (523 &amp;gt;&amp;gt; 2), 130);&lt;br /&gt;
    &lt;br /&gt;
    // left shift&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(523 &amp;lt;&amp;lt; 2)&amp;quot;, (523 &amp;lt;&amp;lt; 2), 2092);&lt;br /&gt;
    &lt;br /&gt;
    // addition&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 + 1)&amp;quot;, (1 + 1), 2);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(1 + 1.1)&amp;quot;, (1 + 1.1), 2.1);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(1.1 + 1)&amp;quot;, (1.1 + 1), 2.1);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(1.1 + 1.1)&amp;quot;, (1.1 + 1.1), 2.2);&lt;br /&gt;
    ensureStringEqual(&amp;quot;\&amp;quot;foo\&amp;quot; + \&amp;quot;bar\&amp;quot;&amp;quot;, &amp;quot;foo&amp;quot; + &amp;quot;bar&amp;quot;, &amp;quot;foobar&amp;quot;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;1.1, 2.2, 3.3&amp;gt; + &amp;lt;4.4, 5.5, 6.6&amp;gt;)&amp;quot;, (&amp;lt;1.1, 2.2, 3.3&amp;gt; + &amp;lt;4.4, 5.5, 6.6&amp;gt;), &amp;lt;5.5, 7.7, 9.9&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;(&amp;lt;1.1, 2.2, 3.3, 4.4&amp;gt; + &amp;lt;4.4, 5.5, 6.6, 3.3&amp;gt;)&amp;quot;, (&amp;lt;1.1, 2.2, 3.3, 4.4&amp;gt; + &amp;lt;4.4, 5.5, 6.6, 3.3&amp;gt;), &amp;lt;5.5, 7.7, 9.9, 7.7&amp;gt;);&lt;br /&gt;
    ensureListEqual(&amp;quot;([1] + 2)&amp;quot;, ([1] + 2), [1,2]);&lt;br /&gt;
    ensureListEqual(&amp;quot;([] + 1.5)&amp;quot;, ([] + 1.5), [1.5]);&lt;br /&gt;
    ensureListEqual(&amp;quot;([\&amp;quot;foo\&amp;quot;] + \&amp;quot;bar\&amp;quot;)&amp;quot;, ([&amp;quot;foo&amp;quot;] + &amp;quot;bar&amp;quot;), [&amp;quot;foo&amp;quot;, &amp;quot;bar&amp;quot;]);&lt;br /&gt;
    ensureListEqual(&amp;quot;([] + &amp;lt;1,2,3&amp;gt;)&amp;quot;, ([] + &amp;lt;1,2,3&amp;gt;), [&amp;lt;1,2,3&amp;gt;]);&lt;br /&gt;
    ensureListEqual(&amp;quot;([] + &amp;lt;1,2,3,4&amp;gt;)&amp;quot;, ([] + &amp;lt;1,2,3,4&amp;gt;), [&amp;lt;1,2,3,4&amp;gt;]);&lt;br /&gt;
    &lt;br /&gt;
    ensureListEqual(&amp;quot;(1 + [2])&amp;quot;, (1 + [2]), [1,2]);&lt;br /&gt;
    ensureListEqual(&amp;quot;(1.0 + [2])&amp;quot;, (1.0 + [2]), [1.0,2]);&lt;br /&gt;
    ensureListEqual(&amp;quot;(1 + [2])&amp;quot;, (&amp;quot;one&amp;quot; + [2]), [&amp;quot;one&amp;quot;,2]);&lt;br /&gt;
    ensureListEqual(&amp;quot;(&amp;lt;1.0,1.0,1.0,1.0&amp;gt; + [2])&amp;quot;, (&amp;lt;1.0,1.0,1.0,1.0&amp;gt; + [2]), [&amp;lt;1.0,1.0,1.0,1.0&amp;gt;,2]);&lt;br /&gt;
    ensureListEqual(&amp;quot;(&amp;lt;1.0,1.0,1.0&amp;gt; + [2])&amp;quot;, (&amp;lt;1.0,1.0,1.0&amp;gt; + [2]), [&amp;lt;1.0,1.0,1.0&amp;gt;,2]);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    // subtraction&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 - 1)&amp;quot;, (1 - 1), 0);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(1 - 0.5)&amp;quot;, (1 - 0.5), 0.5);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(1.5 - 1)&amp;quot;, (1.5 - 1), 0.5);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2.2 - 1.1)&amp;quot;, (2.2 - 1.1), 1.1);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;1.5, 2.5, 3.5&amp;gt; - &amp;lt;4.5, 5.5, 6.5&amp;gt;)&amp;quot;, (&amp;lt;1.5, 2.5, 3.5&amp;gt; - &amp;lt;4.5, 5.5, 6.5&amp;gt;), &amp;lt;-3.0, -3.0, -3.0&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;(&amp;lt;1.5, 2.5, 3.5, 4.5&amp;gt; - &amp;lt;4.5, 5.5, 6.5, 7.5&amp;gt;)&amp;quot;, (&amp;lt;1.5, 2.5, 3.5, 4.5&amp;gt; - &amp;lt;4.5, 5.5, 6.5, 7.5&amp;gt;), &amp;lt;-3.0, -3.0, -3.0, -3.0&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
    // multiplication&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(2 * 3)&amp;quot;, (2 * 3), 6);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2 * 3.5)&amp;quot;, (2 * 3.5), 7.0);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2.5 * 3)&amp;quot;, (2.5 * 3), 7.5);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2.5 * 3.5)&amp;quot;, (2.5 * 3.5), 8.75);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;1.1, 2.2, 3.3&amp;gt; * 2)&amp;quot;, (&amp;lt;1.1, 2.2, 3.3&amp;gt; * 2), &amp;lt;2.2, 4.4, 6.6&amp;gt;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(2 * &amp;lt;1.1, 2.2, 3.3&amp;gt;)&amp;quot;, (&amp;lt;1.1, 2.2, 3.3&amp;gt; * 2), (2 * &amp;lt;1.1, 2.2, 3.3&amp;gt;));&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;2.2, 4.4, 6.6&amp;gt; * 2.0)&amp;quot;, (&amp;lt;2.2, 4.4, 6.6&amp;gt; * 2.0), &amp;lt;4.4, 8.8, 13.2&amp;gt;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(2.0 * &amp;lt;2.2, 4.4, 6.6&amp;gt;)&amp;quot;, (&amp;lt;2.2, 4.4, 6.6&amp;gt; * 2.0), (2.0 * &amp;lt;2.2, 4.4, 6.6&amp;gt;));&lt;br /&gt;
    ensureFloatEqual(&amp;quot;&amp;lt;1,3,-5&amp;gt; * &amp;lt;4,-2,-1&amp;gt;&amp;quot;, &amp;lt;1,3,-5&amp;gt; * &amp;lt;4,-2,-1&amp;gt;, 3.0);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;&amp;lt;-1,0,0&amp;gt; * &amp;lt;0, 0, 0.707, 0.707&amp;gt;&amp;quot;, &amp;lt;-1,0,0&amp;gt; * &amp;lt;0, 0, 0.707, 0.707&amp;gt;, &amp;lt;0,-1, 0&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;(&amp;lt;1.0, 2.0, 3.0, 4.0&amp;gt; * &amp;lt;5.0, 6.0, 7.0, 8.0&amp;gt;)&amp;quot;, (&amp;lt;1.0, 2.0, 3.0, 4.0&amp;gt; * &amp;lt;5.0, 6.0, 7.0, 8.0&amp;gt;), &amp;lt;32.0, 32.0, 56.0, -6.0&amp;gt;);&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    // division&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(2 / 2)&amp;quot;, (2 / 2), 1);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2.2 / 2)&amp;quot;, (2.2 / 2), 1.1);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(3 / 1.5)&amp;quot;, (3 / 1.5), 2.0);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2.2 / 2.0)&amp;quot;, (2.2 / 2.0), 1.1);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;1.0, 2.0, 3.0&amp;gt; / 2)&amp;quot;, (&amp;lt;1.0, 2.0, 3.0&amp;gt; / 2), &amp;lt;0.5, 1.0, 1.5&amp;gt;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;3.0, 6.0, 9.0&amp;gt; / 1.5)&amp;quot;, (&amp;lt;3.0, 6.0, 9.0&amp;gt; / 1.5), &amp;lt;2.0, 4.0, 6.0&amp;gt;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;&amp;lt;-1,0,0&amp;gt; / &amp;lt;0, 0, 0.707, 0.707&amp;gt;&amp;quot;, &amp;lt;-1,0,0&amp;gt; / &amp;lt;0, 0, 0.707, 0.707&amp;gt;, &amp;lt;0,1, 0&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;(&amp;lt;1.0, 2.0, 3.0, 4.0&amp;gt; / &amp;lt;5.0, 6.0, 7.0, 8.0&amp;gt;)&amp;quot;, (&amp;lt;1.0, 2.0, 3.0, 4.0&amp;gt; / &amp;lt;5.0, 6.0, 7.0, 8.0&amp;gt;), &amp;lt;-16.0, 0.0, -8.0, 70.0&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
    // modulo&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(3 % 1)&amp;quot;, (3 % 1), 0);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;1.0, 2.0, 3.0&amp;gt; % &amp;lt;4.0, 5.0, 6.0&amp;gt;)&amp;quot;, (&amp;lt;1.0, 2.0, 3.0&amp;gt; % &amp;lt;4.0, 5.0, 6.0&amp;gt;), &amp;lt;-3.0, 6.0, -3.0&amp;gt;);&lt;br /&gt;
    &lt;br /&gt;
    // assignment&lt;br /&gt;
    integer i = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1;&amp;quot;, i, 1);&lt;br /&gt;
    &lt;br /&gt;
    // addition assignment&lt;br /&gt;
    i = 1;&lt;br /&gt;
    i += 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; i += 1;&amp;quot;, i, 2);&lt;br /&gt;
    &lt;br /&gt;
    // subtraction assignment&lt;br /&gt;
    i = 1;&lt;br /&gt;
    i -= 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; i -= 1;&amp;quot;, i, 0);&lt;br /&gt;
    &lt;br /&gt;
    // multiplication assignment integer *= integer&lt;br /&gt;
    i = 2;&lt;br /&gt;
    i *= 2;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 2; i *= 2;&amp;quot;, i, 4);&lt;br /&gt;
    &lt;br /&gt;
    // multiplication assignment integer *= float&lt;br /&gt;
    i = 1;&lt;br /&gt;
    i *= 0.5;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; i *= 0.5;&amp;quot;, i, 0);&lt;br /&gt;
        &lt;br /&gt;
    // division assignment&lt;br /&gt;
    i = 2;&lt;br /&gt;
    i /= 2;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 2; i /= 2;&amp;quot;, i, 1);&lt;br /&gt;
    &lt;br /&gt;
    // modulo assignment&lt;br /&gt;
    i = 3;&lt;br /&gt;
    i %= 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 3; i %= 1;&amp;quot;, i, 0);&lt;br /&gt;
    &lt;br /&gt;
    // post increment.&lt;br /&gt;
    i = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; (i == 2) &amp;amp;&amp;amp; (i++ == 1)&amp;quot;, (i == 2) &amp;amp;&amp;amp; (i++ == 1), TRUE);&lt;br /&gt;
        &lt;br /&gt;
    // pre increment.&lt;br /&gt;
    i = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; (i == 2) &amp;amp;&amp;amp; (++i == 2)&amp;quot;, (i == 2) &amp;amp;&amp;amp; (++i == 2), TRUE);&lt;br /&gt;
        &lt;br /&gt;
    // post decrement.&lt;br /&gt;
    i = 2;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 2; (i == 1) &amp;amp;&amp;amp; (i-- == 2)&amp;quot;, (i == 1) &amp;amp;&amp;amp; (i-- == 2), TRUE);&lt;br /&gt;
        &lt;br /&gt;
    // pre decrement.&lt;br /&gt;
    i = 2;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 2; (i == 1) &amp;amp;&amp;amp; (--i == 1)&amp;quot;, (i == 1) &amp;amp;&amp;amp; (--i == 1), TRUE);&lt;br /&gt;
    i = 2; --i;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 2; --i&amp;quot;, i, 1);&lt;br /&gt;
    &lt;br /&gt;
    // casting&lt;br /&gt;
    ensureFloatEqual(&amp;quot;((float)2)&amp;quot;, ((float)2), 2.0);&lt;br /&gt;
    ensureStringEqual(&amp;quot;((string)2)&amp;quot;, ((string)2), &amp;quot;2&amp;quot;);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;((integer) 1.5)&amp;quot;, ((integer) 1.5), 1);&lt;br /&gt;
    ensureStringEqual(&amp;quot;((string) 1.5)&amp;quot;, ((string) 1.5), &amp;quot;1.500000&amp;quot;);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;((integer) \&amp;quot;0xF\&amp;quot;)&amp;quot;, ((integer) &amp;quot;0xF&amp;quot;), 15);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;((integer) \&amp;quot;2\&amp;quot;)&amp;quot;, ((integer) &amp;quot;2&amp;quot;), 2);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;((float) \&amp;quot;1.5\&amp;quot;)&amp;quot;, ((float) &amp;quot;1.5&amp;quot;), 1.5);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;((vector) \&amp;quot;&amp;lt;1,2,3&amp;gt;\&amp;quot;)&amp;quot;, ((vector) &amp;quot;&amp;lt;1,2,3&amp;gt;&amp;quot;), &amp;lt;1,2,3&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;((quaternion) \&amp;quot;&amp;lt;1,2,3,4&amp;gt;\&amp;quot;)&amp;quot;, ((quaternion) &amp;quot;&amp;lt;1,2,3,4&amp;gt;&amp;quot;), &amp;lt;1,2,3,4&amp;gt;);&lt;br /&gt;
    ensureStringEqual(&amp;quot;((string) &amp;lt;1,2,3&amp;gt;)&amp;quot;, ((string) &amp;lt;1,2,3&amp;gt;), &amp;quot;&amp;lt;1.00000, 2.00000, 3.00000&amp;gt;&amp;quot;);&lt;br /&gt;
    ensureStringEqual(&amp;quot;((string) &amp;lt;1,2,3,4&amp;gt;)&amp;quot;, ((string) &amp;lt;1,2,3,4&amp;gt;), &amp;quot;&amp;lt;1.00000, 2.00000, 3.00000, 4.00000&amp;gt;&amp;quot;);&lt;br /&gt;
    ensureStringEqual(&amp;quot;((string) [1,2.5,&amp;lt;1,2,3&amp;gt;])&amp;quot;, ((string) [1,2.5,&amp;lt;1,2,3&amp;gt;]), &amp;quot;12.500000&amp;lt;1.000000, 2.000000, 3.000000&amp;gt;&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
    // while&lt;br /&gt;
    i = 0;&lt;br /&gt;
    while(i &amp;lt; 10) ++i;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 0; while(i &amp;lt; 10) ++i&amp;quot;, i, 10);&lt;br /&gt;
    &lt;br /&gt;
    // do while&lt;br /&gt;
    i = 0;&lt;br /&gt;
    do {++i;} while(i &amp;lt; 10);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 0; do {++i;} while(i &amp;lt; 10);&amp;quot;, i, 10);&lt;br /&gt;
    &lt;br /&gt;
    // for&lt;br /&gt;
    for(i = 0; i &amp;lt; 10; ++i);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;for(i = 0; i &amp;lt; 10; ++i);&amp;quot;, i, 10);&lt;br /&gt;
    &lt;br /&gt;
    // jump&lt;br /&gt;
    i = 1;&lt;br /&gt;
    jump SkipAssign;&lt;br /&gt;
    llSetText(&amp;quot;Error&amp;quot;, &amp;lt;1,0,0&amp;gt;, 1); // Inserting this library call causes a save point to be added.&lt;br /&gt;
    i = 2;&lt;br /&gt;
    @SkipAssign;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; jump SkipAssign; i = 2; @SkipAssign;&amp;quot;, i, 1);&lt;br /&gt;
    &lt;br /&gt;
    // return&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;testReturn()&amp;quot;, testReturn(), 1);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;testReturnFloat()&amp;quot;, testReturnFloat(), 1.0);&lt;br /&gt;
    ensureStringEqual(&amp;quot;testReturnString()&amp;quot;, testReturnString(), &amp;quot;Test string&amp;quot;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;testReturnVector()&amp;quot;, testReturnVector(), &amp;lt;1,2,3&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;testReturnRotation()&amp;quot;, testReturnRotation(), &amp;lt;1,2,3,4&amp;gt;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;testReturnVectorNested()&amp;quot;, testReturnVectorNested(), &amp;lt;1,2,3&amp;gt;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;testReturnVectorWithLibraryCall()&amp;quot;, testReturnVectorWithLibraryCall(), &amp;lt;1,2,3&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;testReturnRotationWithLibraryCall()&amp;quot;, testReturnRotationWithLibraryCall(), &amp;lt;1,2,3,4&amp;gt;);&lt;br /&gt;
    &lt;br /&gt;
    // parameters&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;testParameters(1)&amp;quot;, testParameters(1), 2);&lt;br /&gt;
    &lt;br /&gt;
    // variable parameters&lt;br /&gt;
    i = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; testParameters(i)&amp;quot;, testParameters(i), 2);&lt;br /&gt;
    &lt;br /&gt;
    // recursion&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;testRecursion(10)&amp;quot;, testRecursion(10), 0);&lt;br /&gt;
    &lt;br /&gt;
    // globals&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;gInteger&amp;quot;, gInteger, 5);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;gFloat&amp;quot;, gFloat, 1.5);&lt;br /&gt;
    ensureStringEqual(&amp;quot;gString&amp;quot;, gString, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;gVector&amp;quot;, gVector, &amp;lt;1, 2, 3&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;gRot&amp;quot;, gRot, &amp;lt;1, 2, 3, 4&amp;gt;);&lt;br /&gt;
    ensureListEqual(&amp;quot;gList&amp;quot;, gList, [1, 2, 3]);&lt;br /&gt;
    &lt;br /&gt;
    // global assignment&lt;br /&gt;
    gInteger = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;gInteger = 1&amp;quot;, gInteger, 1);&lt;br /&gt;
    &lt;br /&gt;
    gFloat = 0.5;&lt;br /&gt;
    ensureFloatEqual(&amp;quot;gFloat = 0.5&amp;quot;, gFloat, 0.5);&lt;br /&gt;
    &lt;br /&gt;
    gString = &amp;quot;bar&amp;quot;;&lt;br /&gt;
    ensureStringEqual(&amp;quot;gString = \&amp;quot;bar\&amp;quot;&amp;quot;, gString, &amp;quot;bar&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
    gVector = &amp;lt;3,3,3&amp;gt;;&lt;br /&gt;
    ensureVectorEqual(&amp;quot;gVector = &amp;lt;3,3,3&amp;gt;&amp;quot;, gVector, &amp;lt;3,3,3&amp;gt;);&lt;br /&gt;
    &lt;br /&gt;
    gRot = &amp;lt;3,3,3,3&amp;gt;;&lt;br /&gt;
    ensureRotationEqual(&amp;quot;gRot = &amp;lt;3,3,3,3&amp;gt;&amp;quot;, gRot, &amp;lt;3,3,3,3&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
    gList = [4,5,6];&lt;br /&gt;
    ensureListEqual(&amp;quot;gList = [4,5,6]&amp;quot;, gList, [4,5,6]);&lt;br /&gt;
    &lt;br /&gt;
    // negation&lt;br /&gt;
    gVector = &amp;lt;3,3,3&amp;gt;;&lt;br /&gt;
    ensureVectorEqual(&amp;quot;-gVector = &amp;lt;-3,-3,-3&amp;gt;&amp;quot;, -gVector, &amp;lt;-3,-3,-3&amp;gt;);&lt;br /&gt;
    &lt;br /&gt;
    gRot = &amp;lt;3,3,3,3&amp;gt;;&lt;br /&gt;
    ensureRotationEqual(&amp;quot;-gRot = &amp;lt;-3,-3,-3,-3&amp;gt;&amp;quot;, -gRot, &amp;lt;-3,-3,-3,-3&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    // vector accessor&lt;br /&gt;
    vector v;&lt;br /&gt;
    v.x = 3;&lt;br /&gt;
    ensureFloatEqual(&amp;quot;v.x&amp;quot;, v.x, 3);&lt;br /&gt;
    &lt;br /&gt;
    // rotation accessor&lt;br /&gt;
    rotation q;&lt;br /&gt;
    q.s = 5;&lt;br /&gt;
    ensureFloatEqual(&amp;quot;q.s&amp;quot;, q.s, 5);&lt;br /&gt;
    &lt;br /&gt;
    // global vector accessor&lt;br /&gt;
    gVector.y = 17.5;&lt;br /&gt;
    ensureFloatEqual(&amp;quot;gVector.y = 17.5&amp;quot;, gVector.y, 17.5);&lt;br /&gt;
    &lt;br /&gt;
    // global rotation accessor&lt;br /&gt;
    gRot.z = 19.5;&lt;br /&gt;
    ensureFloatEqual(&amp;quot;gRot.z = 19.5&amp;quot;, gRot.z, 19.5);&lt;br /&gt;
    &lt;br /&gt;
    // list equality&lt;br /&gt;
    list l = (list) 5;&lt;br /&gt;
    list l2 = (list) 5;&lt;br /&gt;
    ensureListEqual(&amp;quot;list l = (list) 5; list l2 = (list) 5&amp;quot;, l, l2);&lt;br /&gt;
    ensureListEqual(&amp;quot;list l = (list) 5&amp;quot;, l, [5]);&lt;br /&gt;
    ensureListEqual(&amp;quot;[1.5, 6, &amp;lt;1,2,3&amp;gt;, &amp;lt;1,2,3,4&amp;gt;]&amp;quot;, [1.5, 6, &amp;lt;1,2,3&amp;gt;, &amp;lt;1,2,3,4&amp;gt;], [1.5, 6, &amp;lt;1,2,3&amp;gt;, &amp;lt;1,2,3,4&amp;gt;]);&lt;br /&gt;
&lt;br /&gt;
    // String escaping&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;llStringLength(\&amp;quot;\\\&amp;quot;) == 1&amp;quot;, llStringLength(&amp;quot;\\&amp;quot;), 1);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;llStringLength(\&amp;quot;\\t\&amp;quot;) == 4&amp;quot;, llStringLength(&amp;quot;\t&amp;quot;), 4);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;llStringLength(\&amp;quot;\\n\&amp;quot;) == 1&amp;quot;, llStringLength(&amp;quot;\n&amp;quot;), 1);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;llStringLength(\&amp;quot;\\\&amp;quot;\&amp;quot;) == 1&amp;quot;, llStringLength(&amp;quot;\&amp;quot;&amp;quot;), 1);&lt;br /&gt;
&lt;br /&gt;
    // Nested expression lists&lt;br /&gt;
    ensureStringEqual(&amp;quot;testExpressionLists([testExpressionLists([]), \&amp;quot;bar\&amp;quot;]) == \&amp;quot;foofoobar\&amp;quot;&amp;quot;, testExpressionLists([testExpressionLists([]), &amp;quot;bar&amp;quot;]), &amp;quot;foofoobar&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    touch_start(integer total_number)&lt;br /&gt;
    {&lt;br /&gt;
        llResetTime();&lt;br /&gt;
        tests();&lt;br /&gt;
        llSay(0, &amp;quot;Ran &amp;quot; + (string)(gTestsPassed + gTestsFailed) + &amp;quot; tests in &amp;quot; + (string) llGetTime() + &amp;quot; seconds with &amp;quot; + (string)gTestsFailed + &amp;quot; failures&amp;quot;);&lt;br /&gt;
        &lt;br /&gt;
        // reset globals  &lt;br /&gt;
        gInteger = 5;&lt;br /&gt;
        gFloat = 1.5;&lt;br /&gt;
        gString = &amp;quot;foo&amp;quot;;&lt;br /&gt;
        gVector = &amp;lt;1, 2, 3&amp;gt;;&lt;br /&gt;
        gRot = &amp;lt;1, 2, 3, 4&amp;gt;;&lt;br /&gt;
        gList = [1, 2, 3];&lt;br /&gt;
        gTestsPassed = 0;&lt;br /&gt;
        gTestsFailed = 0;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    http_response(key request_id, integer status, list metadata, string body)&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>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Test_Harness&amp;diff=52675</id>
		<title>LSL Test Harness</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Test_Harness&amp;diff=52675"/>
		<updated>2008-02-04T23:00:19Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Multi-lang}}{{LSL Header}} &lt;br /&gt;
The LSL Test Harness is a platform for testing LSL scripts developed for Linden Lab by i3D Inc. Second Life developers may want to use this to confirm that their  scripts function consistently from update to update. The test harness is freely available (under Creative Commons license: [http://creativecommons.org/licenses/by-sa/2.5/ Attribution-ShareAlike 2.5]) to download and use. &lt;br /&gt;
&lt;br /&gt;
The LSL Test Harness consists of three or more inworld objects. You can create any object, even use the default plywood cube prim, just ensure that you place the appropriate scripts and notecards in the proper objects. &lt;br /&gt;
&lt;br /&gt;
= The Controller =&lt;br /&gt;
The controller provides the interface for you to issue instructions to the test harness. It will listen to your commands on a chat channel and execute them. Alternatively you can make a touch-based controller. &lt;br /&gt;
&lt;br /&gt;
* Rez or create an object, name it Controller.&lt;br /&gt;
* Add the script Controller_Controller (available to copy/paste [[Controller_Controller.lsl | here]]).&lt;br /&gt;
&lt;br /&gt;
= The Coordinator =&lt;br /&gt;
The coordinator handles the communication between the controller and the actual test units themselves. &lt;br /&gt;
&lt;br /&gt;
* Rez or create an object, name it Coordinator&lt;br /&gt;
* Add the following scripts: (available to copy/paste at the linked locations)&lt;br /&gt;
** [[Coordinator_Coordinator.lsl | Coordinator.Coordinator]]&lt;br /&gt;
** [[Coordinator_TestUnits.lsl | Coordinator_TestUnits]]&lt;br /&gt;
** [[Coordinator_TestUnitsReports.lsl | Coordinator_TestUnitsReports]]&lt;br /&gt;
* Now add the notecard [[Coordinator_nc | Coordinator_nc]] and open it&lt;br /&gt;
** If you wish to have the harness send you reports via email, add your email address to the email field&lt;br /&gt;
** If you want the harness to http post the reports, add your url to the Http: field&lt;br /&gt;
&lt;br /&gt;
= The Test Unit(s) =&lt;br /&gt;
The Test Units actually conduct the LSL tests. Therefore they consist of a generic script for running tests, plus the specific script (which you write) which holds the testing code. You may create as many test units as you need. To facilitate development of test scripts, several examples are included in the code repository (here) and these may be used as templates. &lt;br /&gt;
&lt;br /&gt;
* Rez or create an object and call it something descriptive (e.g. Test Unit - Rotations).&lt;br /&gt;
* Add the script [[TestUnit_TestHarness.lsl | TestUnit_TestHarness]]&lt;br /&gt;
* Add the notecard [[TestUnit_nc | TestUnit_nc]]&lt;br /&gt;
** Open the notecard and edit the UnitName and GroupName fields&lt;br /&gt;
*** UnitName is the name you want for this particular test&lt;br /&gt;
*** GroupName specifies a family of tests, in case you want to do something like run all your math testing test units (you&#039;d define a groupName &amp;quot;Math&amp;quot;).&lt;br /&gt;
* Add your test script which should be called [GroupName]_[UnitName]&lt;br /&gt;
** You can use [[TestUnit_TestScript.lsl | TestUnit_TestScript.lsl]] as a template&lt;br /&gt;
** Just add your test lsl to the indicated section and report the result&lt;br /&gt;
* Alternatively, there are some sample test scripts at [[Test_Harness_Test_Units | Test Harness Sample Tests]]&lt;br /&gt;
&lt;br /&gt;
= Commands =&lt;br /&gt;
Once you have the Controller, Coordinator, and all your Test Units rezzed, ensure that they are within chat distance of each other, and then you can issue the following commands in the control channel (default is 1234)&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;ActivateRegistration&#039;&#039;&#039; will make the coordinator round up all test units in chat range&lt;br /&gt;
* &#039;&#039;&#039;ActivateTest&#039;&#039;&#039; will start all selected test units&lt;br /&gt;
* &#039;&#039;&#039;ActivateReport&#039;&#039;&#039; will generate your specified report (chat, email, http)&lt;br /&gt;
* &#039;&#039;&#039;Reset&#039;&#039;&#039; will reset all test units&lt;br /&gt;
* &#039;&#039;&#039;SetTestSelected&#039;&#039;&#039; will specify which test units should execute&lt;br /&gt;
** SetTestSelected::All all test units in range&lt;br /&gt;
** SetTestSelected::[GroupName] all units in that group&lt;br /&gt;
** SetTestSelected::[UnitName] a specific unit&lt;br /&gt;
* &#039;&#039;&#039;SetReportMethod&#039;&#039;&#039; you can choose from three report methods&lt;br /&gt;
** SetReportMethod::CHAT::channel::0 for open chat&lt;br /&gt;
** SetReportMethod::EMAIL::address::you@yourdomain.com&lt;br /&gt;
** SetReportMethod::HTTP::url::www.yoururl.com&lt;br /&gt;
* &#039;&#039;&#039;SetReportType&#039;&#039;&#039; - specify report type as NORMAL, QUITE, VERBOSE, STATS&lt;br /&gt;
** SetReportType::NORMAL&lt;br /&gt;
* &#039;&#039;&#039;SetControlChannel&#039;&#039;&#039; used to change the internal comm channel &lt;br /&gt;
* &#039;&#039;&#039;SetBroadcastChannel&#039;&#039;&#039; chat channel for report output (typically 0)&lt;br /&gt;
&lt;br /&gt;
=Repository for the LSL test harness=&lt;br /&gt;
This is the repository for the LSL test harness - update this wiki as you update the harness! &lt;br /&gt;
&lt;br /&gt;
[[Test Harness Control Buttons]]&lt;br /&gt;
&lt;br /&gt;
[[Test Harness Controller]]&lt;br /&gt;
&lt;br /&gt;
[[Test Harness Test Units]]&lt;br /&gt;
&lt;br /&gt;
[[Test Harness PHP]]&lt;br /&gt;
&lt;br /&gt;
= Tests =&lt;br /&gt;
All known tests should be in [[:Category:Conformance Test]].&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_LSL_Language.lsl&amp;diff=52674</id>
		<title>TestUnit TestScript LSL Language.lsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_LSL_Language.lsl&amp;diff=52674"/>
		<updated>2008-02-04T22:58:46Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Conformance Test]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////            TestUnit_TestScript&lt;br /&gt;
///////             &lt;br /&gt;
///////       &lt;br /&gt;
///////&lt;br /&gt;
///////  This is the test script that should include the code you want to test. &lt;br /&gt;
///////      &lt;br /&gt;
///////              &lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////    &lt;br /&gt;
&lt;br /&gt;
//TestUnit_TestScript    .1 -&amp;gt; initial framework  6.23.2007&lt;br /&gt;
//TestUnit_TestScript    .2 -&amp;gt; tested with minor bug fixes  7.2.2007&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//                  Command Protocol&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        CHAT commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  Chat commands will be on the specified broadcastChannel&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
// AddUnitReport - send Report update to Coordinator on the chat broadcastChannel&lt;br /&gt;
// format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        LINK MESSAGE commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  link message commands will be sent out on the toAllChannel, and recieved on the passFailChannel&lt;br /&gt;
//&lt;br /&gt;
//////// INPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  RunTest - activation command to start test&lt;br /&gt;
//  format example -&amp;gt; RunTest&lt;br /&gt;
//&lt;br /&gt;
//  Report - channel and report type&lt;br /&gt;
//  format example -&amp;gt; Report::controlChannel::0::reportType::NORMAL&lt;br /&gt;
//&lt;br /&gt;
//  Reset - rest the scripts &lt;br /&gt;
//  format example -&amp;gt; Reset&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  passFail - status of test sent on passFailChannel&lt;br /&gt;
//  format example -&amp;gt; PASS&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Global Variables&lt;br /&gt;
&lt;br /&gt;
integer toAllChannel = -255;           // general channel - linked message&lt;br /&gt;
integer passFailChannel = -355;        // test scripts channel for cummunicating pass/fail - linked message&lt;br /&gt;
&lt;br /&gt;
integer debug = 0;                     // level of debug message&lt;br /&gt;
integer debugChannel = DEBUG_CHANNEL;  // output channel for debug messages&lt;br /&gt;
&lt;br /&gt;
integer gTestsPassed = 0;&lt;br /&gt;
integer gTestsFailed = 0;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   ParseCommand&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      string message - command to be parsed&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function calls various other functions or sets globals&lt;br /&gt;
//////////                    depending on message string. Allows external command calls.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
ParseCommand(string message)&lt;br /&gt;
{&lt;br /&gt;
    if(debug &amp;gt; 1)llSay(debugChannel, llGetScriptName()+ &amp;quot;-&amp;gt;ParseCommand: &amp;quot; + message);&lt;br /&gt;
        &lt;br /&gt;
    //reset all scripts &lt;br /&gt;
    if(message == &amp;quot;Reset&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        //reset this script &lt;br /&gt;
        llResetScript();                   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //RunTest()&lt;br /&gt;
    else if(message == &amp;quot;RunTest&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        RunTest();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    //Report()&lt;br /&gt;
    //Example format -&amp;gt; Report::broadcastChannel::0::reportType::NORMAL&lt;br /&gt;
    else if( llSubStringIndex(message, &amp;quot;Report&amp;quot;) != -1 )&lt;br /&gt;
    {&lt;br /&gt;
        //parse the string command into a list&lt;br /&gt;
        list reportParameters = llParseString2List( message, [&amp;quot;::&amp;quot;], [&amp;quot;&amp;quot;] );&lt;br /&gt;
        &lt;br /&gt;
        //find the broadcastChannel label and increment by one&lt;br /&gt;
        integer tempIndex = llListFindList( reportParameters, [&amp;quot;controlChannel&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the broadcastChannel from the list with the index just calculated&lt;br /&gt;
        integer controlChannel = llList2Integer( reportParameters , tempIndex);&lt;br /&gt;
        &lt;br /&gt;
        //find the reportType label and increment by one&lt;br /&gt;
        tempIndex = llListFindList( reportParameters, [&amp;quot;reportType&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the reportType from the list with the index just calculated&lt;br /&gt;
        string reportType = llList2String( reportParameters , tempIndex);&lt;br /&gt;
                &lt;br /&gt;
        //call the Report function with new parameters&lt;br /&gt;
        Report( controlChannel, reportType );&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
} //end ParseCommand&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
// supporting functions&lt;br /&gt;
testPassed(string description, string actual, string expected)&lt;br /&gt;
{&lt;br /&gt;
    ++gTestsPassed;&lt;br /&gt;
    //llSay(0, description);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
testFailed(string description, string actual, string expected)&lt;br /&gt;
{&lt;br /&gt;
    ++gTestsFailed;&lt;br /&gt;
    llSay(0, &amp;quot;FAILED!: &amp;quot; + description + &amp;quot; (&amp;quot; + actual + &amp;quot; expected &amp;quot; + expected + &amp;quot;)&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureTrue(string description, integer actual)&lt;br /&gt;
{&lt;br /&gt;
    if(actual)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) TRUE);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) TRUE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureFalse(string description, integer actual)&lt;br /&gt;
{&lt;br /&gt;
    if(actual)&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) FALSE);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureIntegerEqual(string description, integer actual, integer expected)&lt;br /&gt;
{&lt;br /&gt;
    if(actual == expected)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureFloatEqual(string description, float actual, float expected)&lt;br /&gt;
{&lt;br /&gt;
    if(actual == expected)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureStringEqual(string description, string actual, string expected)&lt;br /&gt;
{&lt;br /&gt;
    if(actual == expected)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureVectorEqual(string description, vector actual, vector expected)&lt;br /&gt;
{&lt;br /&gt;
    if(actual == expected)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureRotationEqual(string description, rotation actual, rotation expected)&lt;br /&gt;
{&lt;br /&gt;
    if(actual == expected)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ensureListEqual(string description, list actual, list expected)&lt;br /&gt;
{&lt;br /&gt;
    if(actual == expected)&lt;br /&gt;
    {&lt;br /&gt;
        testPassed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        testFailed(description, (string) actual, (string) expected);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer gInteger = 5;&lt;br /&gt;
float gFloat = 1.5;&lt;br /&gt;
string gString = &amp;quot;foo&amp;quot;;&lt;br /&gt;
vector gVector = &amp;lt;1, 2, 3&amp;gt;;&lt;br /&gt;
rotation gRot = &amp;lt;1, 2, 3, 4&amp;gt;;&lt;br /&gt;
&lt;br /&gt;
integer testReturn()&lt;br /&gt;
{&lt;br /&gt;
    return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer testParameters(integer param)&lt;br /&gt;
{&lt;br /&gt;
    param = param + 1;&lt;br /&gt;
    return param;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer testRecursion(integer param)&lt;br /&gt;
{&lt;br /&gt;
    if(param &amp;lt;= 0)&lt;br /&gt;
    {&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        return testRecursion(param - 1);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   RunTest&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     link message on passFailChannel test status&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you put the scripts that you want to test&lt;br /&gt;
//////////                  with this unit.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
RunTest()&lt;br /&gt;
{&lt;br /&gt;
     &lt;br /&gt;
    // truth&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;TRUE&amp;quot;, TRUE, TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;FALSE&amp;quot;, FALSE, FALSE);&lt;br /&gt;
    &lt;br /&gt;
    // equality&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE == TRUE)&amp;quot;, (TRUE == TRUE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE == FALSE)&amp;quot;, (TRUE == FALSE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE == FALSE)&amp;quot;, (TRUE == FALSE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE == FALSE)&amp;quot;, (FALSE == FALSE), TRUE);&lt;br /&gt;
    &lt;br /&gt;
    // inequality&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE != TRUE)&amp;quot;, (TRUE != TRUE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE != FALSE)&amp;quot;, (TRUE != FALSE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE != FALSE)&amp;quot;, (TRUE != FALSE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE != FALSE)&amp;quot;, (FALSE != FALSE), FALSE);&lt;br /&gt;
    &lt;br /&gt;
    // and&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE &amp;amp;&amp;amp; TRUE)&amp;quot;, (TRUE &amp;amp;&amp;amp; TRUE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE &amp;amp;&amp;amp; FALSE)&amp;quot;, (TRUE &amp;amp;&amp;amp; FALSE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE &amp;amp;&amp;amp; TRUE)&amp;quot;, (FALSE &amp;amp;&amp;amp; TRUE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE &amp;amp;&amp;amp; FALSE)&amp;quot;, (FALSE &amp;amp;&amp;amp; FALSE), FALSE);&lt;br /&gt;
    &lt;br /&gt;
    // or&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE || TRUE)&amp;quot;, (TRUE || TRUE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(TRUE || FALSE)&amp;quot;, (TRUE || FALSE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE || TRUE)&amp;quot;, (FALSE || TRUE), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(FALSE || FALSE)&amp;quot;, (FALSE || FALSE), FALSE);&lt;br /&gt;
    &lt;br /&gt;
    // not&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(! TRUE)&amp;quot;, (! TRUE), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(! FALSE)&amp;quot;, (! FALSE), TRUE);&lt;br /&gt;
    &lt;br /&gt;
    // greater than&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;gt; 0)&amp;quot;, (1 &amp;gt; 0), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 &amp;gt; 1)&amp;quot;, (0 &amp;gt; 1), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;gt; 1)&amp;quot;, (1 &amp;gt; 1), FALSE);&lt;br /&gt;
    &lt;br /&gt;
    // less than&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 &amp;lt; 1)&amp;quot;, (0 &amp;lt; 1), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;lt; 0)&amp;quot;, (1 &amp;lt; 0), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;lt; 1)&amp;quot;, (1 &amp;lt; 1), FALSE);&lt;br /&gt;
    &lt;br /&gt;
    // greater than or equal&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;gt;= 0)&amp;quot;, (1 &amp;gt;= 0), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 &amp;gt;= 1)&amp;quot;, (0 &amp;gt;= 1), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;gt;= 1)&amp;quot;, (1 &amp;gt;= 1), TRUE);&lt;br /&gt;
    &lt;br /&gt;
    // tess than or equal&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(0 &amp;lt;= 1)&amp;quot;, (0 &amp;lt;= 1), TRUE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;lt;= 0)&amp;quot;, (1 &amp;lt;= 0), FALSE);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 &amp;lt;= 1)&amp;quot;, (1 &amp;lt;= 1), TRUE);&lt;br /&gt;
    &lt;br /&gt;
    // bitwise and&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(10 &amp;amp; 25)&amp;quot;, (10 &amp;amp; 25), 8);&lt;br /&gt;
    &lt;br /&gt;
    // bitwise or&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(10 | 25)&amp;quot;, (10 | 25), 27);&lt;br /&gt;
    &lt;br /&gt;
    // bitwise not&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;~10&amp;quot;, ~10, -11);&lt;br /&gt;
    &lt;br /&gt;
    // xor&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(10 ^ 25)&amp;quot;, (10 ^ 25), 19);&lt;br /&gt;
    &lt;br /&gt;
    // right shift&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(523 &amp;gt;&amp;gt; 2)&amp;quot;, (523 &amp;gt;&amp;gt; 2), 130);&lt;br /&gt;
    &lt;br /&gt;
    // left shift&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(523 &amp;lt;&amp;lt; 2)&amp;quot;, (523 &amp;lt;&amp;lt; 2), 2092);&lt;br /&gt;
    &lt;br /&gt;
    // addition&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 + 1)&amp;quot;, (1 + 1), 2);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(1 + 1.1)&amp;quot;, (1 + 1.1), 2.1);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(1.1 + 1)&amp;quot;, (1.1 + 1), 2.1);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(1.1 + 1.1)&amp;quot;, (1.1 + 1.1), 2.2);&lt;br /&gt;
    ensureStringEqual(&amp;quot;\&amp;quot;foo\&amp;quot; + \&amp;quot;bar\&amp;quot;&amp;quot;, &amp;quot;foo&amp;quot; + &amp;quot;bar&amp;quot;, &amp;quot;foobar&amp;quot;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;1.1, 2.2, 3.3&amp;gt; + &amp;lt;4.4, 5.5, 6.6&amp;gt;)&amp;quot;, (&amp;lt;1.1, 2.2, 3.3&amp;gt; + &amp;lt;4.4, 5.5, 6.6&amp;gt;), &amp;lt;5.5, 7.7, 9.9&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;(&amp;lt;1.1, 2.2, 3.3, 4.4&amp;gt; + &amp;lt;4.4, 5.5, 6.6, 3.3&amp;gt;)&amp;quot;, (&amp;lt;1.1, 2.2, 3.3, 4.4&amp;gt; + &amp;lt;4.4, 5.5, 6.6, 3.3&amp;gt;), &amp;lt;5.5, 7.7, 9.9, 7.7&amp;gt;);&lt;br /&gt;
    ensureListEqual(&amp;quot;([1] + 2)&amp;quot;, ([1] + 2), [1,2]);&lt;br /&gt;
    ensureListEqual(&amp;quot;([] + 1.5)&amp;quot;, ([] + 1.5), [1.5]);&lt;br /&gt;
    ensureListEqual(&amp;quot;([\&amp;quot;foo\&amp;quot;] + \&amp;quot;bar\&amp;quot;)&amp;quot;, ([&amp;quot;foo&amp;quot;] + &amp;quot;bar&amp;quot;), [&amp;quot;foo&amp;quot;, &amp;quot;bar&amp;quot;]);&lt;br /&gt;
    ensureListEqual(&amp;quot;([] + &amp;lt;1,2,3&amp;gt;)&amp;quot;, ([] + &amp;lt;1,2,3&amp;gt;), [&amp;lt;1,2,3&amp;gt;]);&lt;br /&gt;
    ensureListEqual(&amp;quot;([] + &amp;lt;1,2,3,4&amp;gt;)&amp;quot;, ([] + &amp;lt;1,2,3,4&amp;gt;), [&amp;lt;1,2,3,4&amp;gt;]);&lt;br /&gt;
    &lt;br /&gt;
    // subtraction&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(1 - 1)&amp;quot;, (1 - 1), 0);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(1 - 0.5)&amp;quot;, (1 - 0.5), 0.5);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(1.5 - 1)&amp;quot;, (1.5 - 1), 0.5);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2.2 - 1.1)&amp;quot;, (2.2 - 1.1), 1.1);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;1.5, 2.5, 3.5&amp;gt; - &amp;lt;4.5, 5.5, 6.5&amp;gt;)&amp;quot;, (&amp;lt;1.5, 2.5, 3.5&amp;gt; - &amp;lt;4.5, 5.5, 6.5&amp;gt;), &amp;lt;-3.0, -3.0, -3.0&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;(&amp;lt;1.5, 2.5, 3.5, 4.5&amp;gt; - &amp;lt;4.5, 5.5, 6.5, 7.5&amp;gt;)&amp;quot;, (&amp;lt;1.5, 2.5, 3.5, 4.5&amp;gt; - &amp;lt;4.5, 5.5, 6.5, 7.5&amp;gt;), &amp;lt;-3.0, -3.0, -3.0, -3.0&amp;gt;);&lt;br /&gt;
&lt;br /&gt;
    // multiplication&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(2 * 3)&amp;quot;, (2 * 3), 6);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2 * 3.5)&amp;quot;, (2 * 3.5), 7.0);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2.5 * 3)&amp;quot;, (2.5 * 3), 7.5);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2.5 * 3.5)&amp;quot;, (2.5 * 3.5), 8.75);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;1.1, 2.2, 3.3&amp;gt; * 2)&amp;quot;, (&amp;lt;1.1, 2.2, 3.3&amp;gt; * 2), &amp;lt;2.2, 4.4, 6.6&amp;gt;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;2.2, 4.4, 6.6&amp;gt; * 2.0)&amp;quot;, (&amp;lt;2.2, 4.4, 6.6&amp;gt; * 2.0), &amp;lt;4.4, 8.8, 13.2&amp;gt;);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(&amp;lt;1.0, 2.0, 3.0&amp;gt; * &amp;lt;4.0, 5.0, 6.0&amp;gt;)&amp;quot;, (&amp;lt;1.0, 2.0, 3.0&amp;gt; * &amp;lt;4.0, 5.0, 6.0&amp;gt;), 32.0);&lt;br /&gt;
&lt;br /&gt;
    // division&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(2 / 2)&amp;quot;, (2 / 2), 1);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2.2 / 2)&amp;quot;, (2.2 / 2), 1.1);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(3 / 1.5)&amp;quot;, (3 / 1.5), 2.0);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;(2.2 / 2.0)&amp;quot;, (2.2 / 2.0), 1.1);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;1.0, 2.0, 3.0&amp;gt; / 2)&amp;quot;, (&amp;lt;1.0, 2.0, 3.0&amp;gt; / 2), &amp;lt;0.5, 1.0, 1.5&amp;gt;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;3.0, 6.0, 9.0&amp;gt; / 1.5)&amp;quot;, (&amp;lt;3.0, 6.0, 9.0&amp;gt; / 1.5), &amp;lt;2.0, 4.0, 6.0&amp;gt;);&lt;br /&gt;
    &lt;br /&gt;
    // modulo&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;(3 % 1)&amp;quot;, (3 % 1), 0);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;(&amp;lt;1.0, 2.0, 3.0&amp;gt; % &amp;lt;4.0, 5.0, 6.0&amp;gt;)&amp;quot;, (&amp;lt;1.0, 2.0, 3.0&amp;gt; % &amp;lt;4.0, 5.0, 6.0&amp;gt;), &amp;lt;-3.0, 6.0, -3.0&amp;gt;);&lt;br /&gt;
    &lt;br /&gt;
    // assignment&lt;br /&gt;
    integer i = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1;&amp;quot;, i, 1);&lt;br /&gt;
    &lt;br /&gt;
    // addition assignment&lt;br /&gt;
    i = 1;&lt;br /&gt;
    i += 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; i += 1;&amp;quot;, i, 2);&lt;br /&gt;
    &lt;br /&gt;
    // subtraction assignment&lt;br /&gt;
    i = 1;&lt;br /&gt;
    i -= 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; i -= 1;&amp;quot;, i, 0);&lt;br /&gt;
    &lt;br /&gt;
    // multiplication assignment&lt;br /&gt;
    i = 2;&lt;br /&gt;
    i *= 2;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 2; i *= 2;&amp;quot;, i, 4);&lt;br /&gt;
    &lt;br /&gt;
    // division assignment&lt;br /&gt;
    i = 2;&lt;br /&gt;
    i /= 2;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 2; i /= 2;&amp;quot;, i, 1);&lt;br /&gt;
    &lt;br /&gt;
    // modulo assignment&lt;br /&gt;
    i = 3;&lt;br /&gt;
    i %= 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 3; i %= 1;&amp;quot;, i, 0);&lt;br /&gt;
    &lt;br /&gt;
    // post increment.&lt;br /&gt;
    i = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; (i == 2) &amp;amp;&amp;amp; (i++ == 1)&amp;quot;, (i == 2) &amp;amp;&amp;amp; (i++ == 1), TRUE);&lt;br /&gt;
        &lt;br /&gt;
    // pre increment.&lt;br /&gt;
    i = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; (i == 2) &amp;amp;&amp;amp; (++i == 2)&amp;quot;, (i == 2) &amp;amp;&amp;amp; (++i == 2), TRUE);&lt;br /&gt;
        &lt;br /&gt;
    // post decrement.&lt;br /&gt;
    i = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; (i == 0) &amp;amp;&amp;amp; (i-- == 1)&amp;quot;, (i == 0) &amp;amp;&amp;amp; (i-- == 1), TRUE);&lt;br /&gt;
        &lt;br /&gt;
    // pre decrement.&lt;br /&gt;
    i = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; (i == 0) &amp;amp;&amp;amp; (--i == 0)&amp;quot;, (i == 0) &amp;amp;&amp;amp; (--i == 0), TRUE);&lt;br /&gt;
    &lt;br /&gt;
    // casting&lt;br /&gt;
    ensureFloatEqual(&amp;quot;((float)2)&amp;quot;, ((float)2), 2.0);&lt;br /&gt;
    ensureStringEqual(&amp;quot;((string)2)&amp;quot;, ((string)2), &amp;quot;2&amp;quot;);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;((integer) 1.5)&amp;quot;, ((integer) 1.5), 1);&lt;br /&gt;
    ensureStringEqual(&amp;quot;((string) 1.5)&amp;quot;, ((string) 1.5), &amp;quot;1.500000&amp;quot;);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;((integer) \&amp;quot;0xF\&amp;quot;)&amp;quot;, ((integer) &amp;quot;0xF&amp;quot;), 15);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;((integer) \&amp;quot;2\&amp;quot;)&amp;quot;, ((integer) &amp;quot;2&amp;quot;), 2);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;((float) \&amp;quot;1.5\&amp;quot;)&amp;quot;, ((float) &amp;quot;1.5&amp;quot;), 1.5);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;((vector) \&amp;quot;&amp;lt;1,2,3&amp;gt;\&amp;quot;)&amp;quot;, ((vector) &amp;quot;&amp;lt;1,2,3&amp;gt;&amp;quot;), &amp;lt;1,2,3&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;((quaternion) \&amp;quot;&amp;lt;1,2,3,4&amp;gt;\&amp;quot;)&amp;quot;, ((quaternion) &amp;quot;&amp;lt;1,2,3,4&amp;gt;&amp;quot;), &amp;lt;1,2,3,4&amp;gt;);&lt;br /&gt;
    ensureStringEqual(&amp;quot;((string) &amp;lt;1,2,3&amp;gt;)&amp;quot;, ((string) &amp;lt;1,2,3&amp;gt;), &amp;quot;&amp;lt;1.00000, 2.00000, 3.00000&amp;gt;&amp;quot;);&lt;br /&gt;
    ensureStringEqual(&amp;quot;((string) &amp;lt;1,2,3,4&amp;gt;)&amp;quot;, ((string) &amp;lt;1,2,3,4&amp;gt;), &amp;quot;&amp;lt;1.00000, 2.00000, 3.00000, 4.00000&amp;gt;&amp;quot;);&lt;br /&gt;
    ensureStringEqual(&amp;quot;((string) [1,2.5,&amp;lt;1,2,3&amp;gt;])&amp;quot;, ((string) [1,2.5,&amp;lt;1,2,3&amp;gt;]), &amp;quot;12.500000&amp;lt;1.000000, 2.000000, 3.000000&amp;gt;&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
    // while&lt;br /&gt;
    i = 0;&lt;br /&gt;
    while(i &amp;lt; 10) ++i;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 0; while(i &amp;lt; 10) ++i&amp;quot;, i, 10);&lt;br /&gt;
    &lt;br /&gt;
    // do while&lt;br /&gt;
    i = 0;&lt;br /&gt;
    do {++i;} while(i &amp;lt; 10);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 0; do {++i;} while(i &amp;lt; 10);&amp;quot;, i, 10);&lt;br /&gt;
    &lt;br /&gt;
    // for&lt;br /&gt;
    for(i = 0; i &amp;lt; 10; ++i);&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;for(i = 0; i &amp;lt; 10; ++i);&amp;quot;, i, 10);&lt;br /&gt;
    &lt;br /&gt;
    // jump&lt;br /&gt;
    i = 1;&lt;br /&gt;
    jump SkipAssign;&lt;br /&gt;
    i = 2;&lt;br /&gt;
    @SkipAssign;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; jump SkipAssign; i = 2; @SkipAssign;&amp;quot;, i, 1);&lt;br /&gt;
    &lt;br /&gt;
    // return&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;testReturn()&amp;quot;, testReturn(), 1);&lt;br /&gt;
    &lt;br /&gt;
    // parameters&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;testParameters(1)&amp;quot;, testParameters(1), 2);&lt;br /&gt;
    &lt;br /&gt;
    // variable parameters&lt;br /&gt;
    i = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;i = 1; testParameters(i)&amp;quot;, testParameters(i), 2);&lt;br /&gt;
    &lt;br /&gt;
    // recursion&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;testRecursion(10)&amp;quot;, testRecursion(10), 0);&lt;br /&gt;
    &lt;br /&gt;
    // globals&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;gInteger&amp;quot;, gInteger, 5);&lt;br /&gt;
    ensureFloatEqual(&amp;quot;gFloat&amp;quot;, gFloat, 1.5);&lt;br /&gt;
    ensureStringEqual(&amp;quot;gString&amp;quot;, gString, &amp;quot;foo&amp;quot;);&lt;br /&gt;
    ensureVectorEqual(&amp;quot;gVector&amp;quot;, gVector, &amp;lt;1, 2, 3&amp;gt;);&lt;br /&gt;
    ensureRotationEqual(&amp;quot;gRot&amp;quot;, gRot, &amp;lt;1, 2, 3, 4&amp;gt;);&lt;br /&gt;
    &lt;br /&gt;
    // global assignment&lt;br /&gt;
    gInteger = 1;&lt;br /&gt;
    ensureIntegerEqual(&amp;quot;gInteger = 1&amp;quot;, gInteger, 1);&lt;br /&gt;
    &lt;br /&gt;
    gFloat = 0.5;&lt;br /&gt;
    ensureFloatEqual(&amp;quot;gFloat = 0.5&amp;quot;, gFloat, 0.5);&lt;br /&gt;
    &lt;br /&gt;
    gString = &amp;quot;bar&amp;quot;;&lt;br /&gt;
    ensureStringEqual(&amp;quot;gString = \&amp;quot;bar\&amp;quot;&amp;quot;, gString, &amp;quot;bar&amp;quot;);&lt;br /&gt;
    &lt;br /&gt;
    gVector = &amp;lt;3,3,3&amp;gt;;&lt;br /&gt;
    ensureVectorEqual(&amp;quot;gVector = &amp;lt;3,3,3&amp;gt;&amp;quot;, gVector, &amp;lt;3,3,3&amp;gt;);&lt;br /&gt;
    &lt;br /&gt;
    gRot = &amp;lt;3,3,3,3&amp;gt;;&lt;br /&gt;
    ensureRotationEqual(&amp;quot;gRot = &amp;lt;3,3,3,3&amp;gt;&amp;quot;, gRot, &amp;lt;3,3,3,3&amp;gt;);&lt;br /&gt;
    &lt;br /&gt;
    // vector accessor&lt;br /&gt;
    vector v;&lt;br /&gt;
    v.x = 3;&lt;br /&gt;
    ensureFloatEqual(&amp;quot;v.x&amp;quot;, v.x, 3);&lt;br /&gt;
    &lt;br /&gt;
    // rotation accessor&lt;br /&gt;
    rotation q;&lt;br /&gt;
    q.s = 5;&lt;br /&gt;
    ensureFloatEqual(&amp;quot;q.s&amp;quot;, q.s, 5);&lt;br /&gt;
    &lt;br /&gt;
    // global vector accessor&lt;br /&gt;
    gVector.y = 17.5;&lt;br /&gt;
    ensureFloatEqual(&amp;quot;gVector.y = 17.5&amp;quot;, gVector.y, 17.5);&lt;br /&gt;
    &lt;br /&gt;
    // global rotation accessor&lt;br /&gt;
    gRot.z = 19.5;&lt;br /&gt;
    ensureFloatEqual(&amp;quot;gRot.z = 19.5&amp;quot;, gRot.z, 19.5);&lt;br /&gt;
    &lt;br /&gt;
    // list equality&lt;br /&gt;
    list l = (list) 5;&lt;br /&gt;
    list l2 = (list) 5;&lt;br /&gt;
    ensureListEqual(&amp;quot;list l = (list) 5; list l2 = (list) 5&amp;quot;, l, l2);&lt;br /&gt;
    ensureListEqual(&amp;quot;list l = (list) 5&amp;quot;, l, [5]);&lt;br /&gt;
    ensureListEqual(&amp;quot;[1.5, 6, &amp;lt;1,2,3&amp;gt;, &amp;lt;1,2,3,4&amp;gt;]&amp;quot;, [1.5, 6, &amp;lt;1,2,3&amp;gt;, &amp;lt;1,2,3,4&amp;gt;], [1.5, 6, &amp;lt;1,2,3&amp;gt;, &amp;lt;1,2,3,4&amp;gt;]);&lt;br /&gt;
    &lt;br /&gt;
    if (gTestsFailed &amp;gt; 0) {&lt;br /&gt;
        llMessageLinked(LINK_SET, passFailChannel, &amp;quot;FAIL&amp;quot;, NULL_KEY);  &lt;br /&gt;
    } else {&lt;br /&gt;
        llMessageLinked(LINK_SET, passFailChannel, &amp;quot;PASS&amp;quot;, NULL_KEY);&lt;br /&gt;
    }    &lt;br /&gt;
    &lt;br /&gt;
    // reset globals  &lt;br /&gt;
    gInteger = 5;&lt;br /&gt;
    gFloat = 1.5;&lt;br /&gt;
    gString = &amp;quot;foo&amp;quot;;&lt;br /&gt;
    gVector = &amp;lt;1, 2, 3&amp;gt;;&lt;br /&gt;
    gRot = &amp;lt;1, 2, 3, 4&amp;gt;;&lt;br /&gt;
    gTestsPassed = 0;&lt;br /&gt;
    gTestsFailed = 0;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Report&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      broadcastChannel - chat channel to send report&lt;br /&gt;
//////////                  reportType - determines length and content of report type&lt;br /&gt;
//////////                                         -&amp;gt; NORMAL - failures and summary information&lt;br /&gt;
//////////                                         -&amp;gt; QUITE - summary information only&lt;br /&gt;
//////////                                         -&amp;gt; VERBOSE - everything&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     llSay on broadcastChannel &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you design the three level of reports&lt;br /&gt;
//////////                  avaliable upon request by the Coordinator&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Report( integer broadcastChannel, string reportType )&lt;br /&gt;
{&lt;br /&gt;
    string reportString;&lt;br /&gt;
    &lt;br /&gt;
    //Normal - moderate level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;NORMAL&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
        reportString = &amp;quot;&amp;quot;;  //add what you would like to report here !!!!!!&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //QUITE - shortest level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;QUIET&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
        reportString = &amp;quot;&amp;quot;;  //add what you would like to report here !!!!!!&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //VERBOSE - highest level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;VERBOSE&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
        reportString = &amp;quot;&amp;quot;;  //add what you would like to report here !!!!!!&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //AddUnitReport()&lt;br /&gt;
    //send to Coordinator on the broadcastChannel the selected report&lt;br /&gt;
    //format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
    llSay( broadcastChannel, &amp;quot;AddUnitReport::unitKey::&amp;quot; + (string)llGetKey() + &amp;quot;::Report::&amp;quot; + reportString);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Initialize&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function initializes any variables or functions necessary&lt;br /&gt;
//////////                  to get us started&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Initialize()&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE//&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                          DEFAULT STATE                                            //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  State Entry of default state                     //&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
   state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
////////////////////////////////////////////////////////&lt;br /&gt;
//  On Rez of default state                           //&lt;br /&gt;
////////////////////////////////////////////////////////    &lt;br /&gt;
    on_rez(integer start_param)&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  Link Message of default state                    //&lt;br /&gt;
///////////////////////////////////////////////////////   &lt;br /&gt;
    link_message(integer sender_number, integer number, string message, key id)&lt;br /&gt;
    {&lt;br /&gt;
        //if link message is on the correct channel&lt;br /&gt;
        if(number == toAllChannel)&lt;br /&gt;
        {&lt;br /&gt;
            //treat as command input&lt;br /&gt;
            ParseCommand(message);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    } //end of link message&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
} // end default&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_Math_TRIG.lsl&amp;diff=52673</id>
		<title>TestUnit TestScript Math TRIG.lsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_Math_TRIG.lsl&amp;diff=52673"/>
		<updated>2008-02-04T22:58:29Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Conformance Test]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////            TestUnit_TestScript&lt;br /&gt;
///////             &lt;br /&gt;
///////            Math_TRIG&lt;br /&gt;
///////&lt;br /&gt;
///////  This is the test script for the trigonometry math functions.  &lt;br /&gt;
///////      &lt;br /&gt;
///////              &lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////    &lt;br /&gt;
&lt;br /&gt;
//TestUnit_TestScript    .1 -&amp;gt; initial framework  6.23.2007&lt;br /&gt;
//TestUnit_TestScript    .2 -&amp;gt; tested with minor bug fixes  7.2.2007&lt;br /&gt;
&lt;br /&gt;
//Math_TRIG              .1 -&amp;gt; modified from TestUnit_TestScript base to test trig math functions  7.3.2007&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//                  Command Protocol&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        CHAT commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  Chat commands will be on the specified broadcastChannel&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
// AddUnitReport - send Report update to Coordinator on the chat broadcastChannel&lt;br /&gt;
// format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        LINK MESSAGE commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  link message commands will be sent out on the toAllChannel, and recieved on the passFailChannel&lt;br /&gt;
//&lt;br /&gt;
//////// INPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  RunTest - activation command to start test&lt;br /&gt;
//  format example -&amp;gt; RunTest&lt;br /&gt;
//&lt;br /&gt;
//  Report - channel and report type&lt;br /&gt;
//  format example -&amp;gt; Report::controlChannel::0::reportType::NORMAL&lt;br /&gt;
//&lt;br /&gt;
//  Reset - rest the scripts &lt;br /&gt;
//  format example -&amp;gt; Reset&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  passFail - status of test sent on passFailChannel&lt;br /&gt;
//  format example -&amp;gt; PASS&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Global Variables&lt;br /&gt;
&lt;br /&gt;
integer toAllChannel = -255;           // general channel - linked message&lt;br /&gt;
integer passFailChannel = -355;        // test scripts channel for cummunicating pass/fail - linked message&lt;br /&gt;
&lt;br /&gt;
integer debug = 0;                     // level of debug message&lt;br /&gt;
integer debugChannel = DEBUG_CHANNEL;  // output channel for debug messages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer llAcosPASS;                    // These are global pass/fail&lt;br /&gt;
integer llAsinPASS;                    // indicators for the various&lt;br /&gt;
integer llAtan2PASS;                   // Math trig functions that are &lt;br /&gt;
integer llCosPASS;                     // being tested. These variables &lt;br /&gt;
integer llSinPASS;                     // are used in the Run Test and&lt;br /&gt;
integer llTanPASS;                     // Report Functions of this script. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   ParseCommand&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      string message - command to be parsed&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function calls various other functions or sets globals&lt;br /&gt;
//////////                    depending on message string. Allows external command calls.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
ParseCommand(string message)&lt;br /&gt;
{&lt;br /&gt;
    if(debug &amp;gt; 1)llSay(debugChannel, llGetScriptName()+ &amp;quot;-&amp;gt;ParseCommand: &amp;quot; + message);&lt;br /&gt;
        &lt;br /&gt;
    //reset all scripts &lt;br /&gt;
    if(message == &amp;quot;Reset&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        //reset this script &lt;br /&gt;
        llResetScript();                   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //RunTest()&lt;br /&gt;
    else if(message == &amp;quot;RunTest&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        RunTest();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    //Report()&lt;br /&gt;
    //Example format -&amp;gt; Report::broadcastChannel::0::reportType::NORMAL&lt;br /&gt;
    else if( llSubStringIndex(message, &amp;quot;Report&amp;quot;) != -1 )&lt;br /&gt;
    {&lt;br /&gt;
        //parse the string command into a list&lt;br /&gt;
        list reportParameters = llParseString2List( message, [&amp;quot;::&amp;quot;], [&amp;quot;&amp;quot;] );&lt;br /&gt;
        &lt;br /&gt;
        //find the broadcastChannel label and increment by one&lt;br /&gt;
        integer tempIndex = llListFindList( reportParameters, [&amp;quot;controlChannel&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the broadcastChannel from the list with the index just calculated&lt;br /&gt;
        integer controlChannel = llList2Integer( reportParameters , tempIndex);&lt;br /&gt;
        &lt;br /&gt;
        //find the reportType label and increment by one&lt;br /&gt;
        tempIndex = llListFindList( reportParameters, [&amp;quot;reportType&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the reportType from the list with the index just calculated&lt;br /&gt;
        string reportType = llList2String( reportParameters , tempIndex);&lt;br /&gt;
                &lt;br /&gt;
        //call the Report function with new parameters&lt;br /&gt;
        Report( controlChannel, reportType );&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
} //end ParseCommand&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   RunTest&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     link message on passFailChannel test status&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you put the scripts that you want to test&lt;br /&gt;
//////////                  with this unit.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
RunTest()&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
     ///////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: float llAcos( float val );&lt;br /&gt;
     // Returns a float that is the arccosine in radians of val&lt;br /&gt;
     // • float     val     –     val must fall in the range [-1.0, 1.0]. (-1.0 &amp;lt;= val &amp;lt;= 1.0)     &lt;br /&gt;
     ///////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
     //initialize a pass variable to TRUE &lt;br /&gt;
     llAcosPASS = 0;&lt;br /&gt;
          &lt;br /&gt;
     //compare known cosine of some angles&lt;br /&gt;
     if( (string)3.141593 == (string)llAcos( -1.0 ) &amp;amp;&lt;br /&gt;
     		(string)1.570796 == (string)llAcos( 0.0 ) &amp;amp;&lt;br /&gt;
     		(string)0.0 == (string)llAcos( 1.0 ) )&lt;br /&gt;
     {&lt;br /&gt;
         llAcosPASS = 1;    &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     ///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: float llAsin( float val );&lt;br /&gt;
     // Returns a float that is the arcsine in radians of val&lt;br /&gt;
     // • float     val     –     must fall in the range [-1.0, 1.0]. (-1.0 &amp;lt;= val &amp;lt;= 1.0)     &lt;br /&gt;
     ////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     &lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llAsinPASS = 0;&lt;br /&gt;
     &lt;br /&gt;
     //test four sets of vector configurations to hardcoded values&lt;br /&gt;
     if( (string)-1.570796 == (string)llAsin( -1.0) &amp;amp;&lt;br /&gt;
     		(string)0.0 == (string)llAsin( 0.0 ) &amp;amp;&lt;br /&gt;
     		(string)1.570796 == (string)llAsin( 1.0 ) )&lt;br /&gt;
     {&lt;br /&gt;
         llAsinPASS = 1; &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
     /////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: float llAtan2( float y, float x );&lt;br /&gt;
     // Returns a float that is the arctangent2 of y, x.&lt;br /&gt;
     // • float     y             &lt;br /&gt;
     // • float     x             &lt;br /&gt;
     // Similar to the arctangent(y/x) except it utilizes the signs of x &amp;amp; y to &lt;br /&gt;
     // determine the quadrant. Returns zero if x and y are zero. &lt;br /&gt;
     ////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     &lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llAtan2PASS = 0;&lt;br /&gt;
         &lt;br /&gt;
     //test four sets of configurations to hardcoded values&lt;br /&gt;
     if( (string)0.0 == (string)llAtan2( 0.0, 0.0) &amp;amp;&lt;br /&gt;
     		(string)0.0 ==  (string)llAtan2( 0.0, 1.0 ) &amp;amp;&lt;br /&gt;
     		(string)0.785398 == (string)llAtan2( 1.0, 1.0 ) )&lt;br /&gt;
     {&lt;br /&gt;
         llAtan2PASS = 1; &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     //////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: float llCos( float theta );&lt;br /&gt;
     // Returns a float that is the cosine of theta.&lt;br /&gt;
     // • float     theta     –     angle expressed in radians.     &lt;br /&gt;
     /////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     &lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llCosPASS = 0;&lt;br /&gt;
       &lt;br /&gt;
     //test four sets of configurations to hardcoded values&lt;br /&gt;
     if( (string)1.0 == (string)llCos( 0.0 ) &amp;amp;&lt;br /&gt;
     		(string)0.540302 ==  (string)llCos( 1.0 ) &amp;amp;&lt;br /&gt;
     		(string)0.540302 == (string)llCos( -1.0 ) )&lt;br /&gt;
     {&lt;br /&gt;
         llCosPASS = 1; &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
       ///////////////////////////////////////////////////////////////////////////////////    &lt;br /&gt;
       // Function: float llSin( float theta );&lt;br /&gt;
       // Returns a float that is the sine of theta.&lt;br /&gt;
       // • float     theta     –     angle expressed in radians.     &lt;br /&gt;
       //////////////////////////////////////////////////////////////////////////////////   &lt;br /&gt;
     &lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llSinPASS = 0;&lt;br /&gt;
       &lt;br /&gt;
     //test four sets of configurations to hardcoded values&lt;br /&gt;
     if( (string)0.0 == (string)llSin( 0.0 ) &amp;amp;&lt;br /&gt;
     		(string)0.841471 ==  (string)llSin( 1.0 ) &amp;amp;&lt;br /&gt;
     		(string)-0.841471 == (string)llSin( -1.0 ) )&lt;br /&gt;
     {&lt;br /&gt;
         llSinPASS = 1; &lt;br /&gt;
     }   &lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
     /////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: float llTan( float theta );&lt;br /&gt;
     // Returns a float that is the tangent of theta.&lt;br /&gt;
     // • float     theta     –     angle expressed in radians.&lt;br /&gt;
     /////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     &lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llTanPASS = 0;&lt;br /&gt;
       &lt;br /&gt;
     //test four sets of configurations to hardcoded values&lt;br /&gt;
     if( (string)0.0 == (string)llTan( 0.0 ) &amp;amp;&lt;br /&gt;
     		(string)1.557408 ==  (string)llTan( 1.0 ) &amp;amp;&lt;br /&gt;
     		(string)-1.557408 == (string)llTan( -1.0 ) )&lt;br /&gt;
     {&lt;br /&gt;
         llTanPASS = 1; &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
     //check to see if any failures occured. &lt;br /&gt;
     integer pass = llAcosPASS &amp;amp;&lt;br /&gt;
                    llAsinPASS &amp;amp;&lt;br /&gt;
                    llAtan2PASS &amp;amp;&lt;br /&gt;
                    llCosPASS &amp;amp;&lt;br /&gt;
                    llSinPASS &amp;amp;&lt;br /&gt;
                    llTanPASS;&lt;br /&gt;
&lt;br /&gt;
     // if all of the individual &lt;br /&gt;
     if( pass )&lt;br /&gt;
     {&lt;br /&gt;
       llMessageLinked(LINK_SET, passFailChannel, &amp;quot;PASS&amp;quot;, NULL_KEY);&lt;br /&gt;
     }&lt;br /&gt;
     else&lt;br /&gt;
     {&lt;br /&gt;
       llMessageLinked(LINK_SET, passFailChannel, &amp;quot;FAIL&amp;quot;, NULL_KEY);&lt;br /&gt;
     }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Report&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      broadcastChannel - chat channel to send report&lt;br /&gt;
//////////                  reportType - determines length and content of report type&lt;br /&gt;
//////////                                         -&amp;gt; NORMAL - failures and summary information&lt;br /&gt;
//////////                                         -&amp;gt; QUITE - summary information only&lt;br /&gt;
//////////                                         -&amp;gt; VERBOSE - everything&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     llSay on broadcastChannel &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you design the three level of reports&lt;br /&gt;
//////////                  avaliable upon request by the Coordinator&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Report( integer controlChannel, string reportType )&lt;br /&gt;
{&lt;br /&gt;
    //this string will be sent out reguardless of reporting mode&lt;br /&gt;
    string reportString;&lt;br /&gt;
 &lt;br /&gt;
    // PASS or FAIL wording for the report&lt;br /&gt;
    string llAcosPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llAsinPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llAtan2PASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llCosPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llSinPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llTanPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
    //translate integer conditional into text string for the report. &lt;br /&gt;
    if ( llAcosPASS )&lt;br /&gt;
    {&lt;br /&gt;
          llAcosPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llAsinPASS )&lt;br /&gt;
    {&lt;br /&gt;
          llAsinPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llAtan2PASS )&lt;br /&gt;
    {&lt;br /&gt;
          llAtan2PASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llCosPASS  )&lt;br /&gt;
    {&lt;br /&gt;
          llCosPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llSinPASS )&lt;br /&gt;
    {&lt;br /&gt;
          llSinPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llTanPASS )&lt;br /&gt;
    {&lt;br /&gt;
          llTanPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
   &lt;br /&gt;
    //Normal - moderate level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;NORMAL&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
      reportString = &amp;quot;Function: float llAcos( float val ) -&amp;gt; &amp;quot; &lt;br /&gt;
                                                + llAcosPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: float llAsin( float val ) -&amp;gt;&amp;quot; &lt;br /&gt;
                                                + llAsinPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: float llAtan2( float y, float x ) -&amp;gt; &amp;quot; &lt;br /&gt;
                                                + llAtan2PASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: float llCos( float theta ) -&amp;gt; &amp;quot; &lt;br /&gt;
                                                + llCosPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: float llSin( float theta ) -&amp;gt; &amp;quot; &lt;br /&gt;
                                                + llSinPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: float llTan( float theta ) -&amp;gt; &amp;quot;&lt;br /&gt;
                                                + llTanPASSstring + &amp;quot;\n&amp;quot;;&lt;br /&gt;
       &lt;br /&gt;
    } // end normal   &lt;br /&gt;
    &lt;br /&gt;
    //VERBOSE - highest level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;VERBOSE&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
             reportString = &amp;quot;///////////////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot;+&lt;br /&gt;
             	&amp;quot;// Function: float llAcos( float val );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a float that is the arccosine in radians of val&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • float     val     –     val must fall in the range [-1.0, 1.0]. (-1.0 &amp;lt;= val &amp;lt;= 1.0)     &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;///////////////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llAcosPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
     &lt;br /&gt;
				&amp;quot;///////////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: float llAsin( float val );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a float that is the arcsine in radians of val&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • float     val     –     must fall in the range [-1.0, 1.0]. (-1.0 &amp;lt;= val &amp;lt;= 1.0)     &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;////////////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llAsinPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				&lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: float llAtan2( float y, float x );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a float that is the arctangent2 of y, x.&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • float     y             &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • float     x             &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Similar to the arctangent(y/x) except it utilizes the signs of x &amp;amp; y to &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// determine the quadrant. Returns zero if x and y are zero. &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llAtan2PASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				     &lt;br /&gt;
				&amp;quot;//////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: float llCos( float theta );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a float that is the cosine of theta.&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • float     theta     –     angle expressed in radians.     &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llCosPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				&lt;br /&gt;
				     &lt;br /&gt;
				&amp;quot;///////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +    &lt;br /&gt;
				&amp;quot;// Function: float llSin( float theta );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a float that is the sine of theta.&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • float     theta     –     angle expressed in radians.     &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;//////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +   &lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llSinPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				&lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: float llTan( float theta );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a float that is the tangent of theta.&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • float     theta     –     angle expressed in radians.&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llTanPASSstring + &amp;quot;\n\n&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    } // end verbose&lt;br /&gt;
        &lt;br /&gt;
    //AddUnitReport()&lt;br /&gt;
    //send to Coordinator on the broadcastChannel the selected report&lt;br /&gt;
    //format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
    llSay( controlChannel, &amp;quot;AddUnitReport::unitKey::&amp;quot; + (string)llGetKey() + &amp;quot;::Report::&amp;quot; + reportString);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Initialize&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function initializes any variables or functions necessary&lt;br /&gt;
//////////                  to get us started&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Initialize()&lt;br /&gt;
{&lt;br /&gt;
    llSetText( &amp;quot;Math Trig&amp;quot;, &amp;lt;255,255,255&amp;gt;, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE//&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                          DEFAULT STATE                                            //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  State Entry of default state                     //&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
   state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
////////////////////////////////////////////////////////&lt;br /&gt;
//  On Rez of default state                           //&lt;br /&gt;
////////////////////////////////////////////////////////    &lt;br /&gt;
    on_rez(integer start_param)&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  Link Message of default state                    //&lt;br /&gt;
///////////////////////////////////////////////////////   &lt;br /&gt;
    link_message(integer sender_number, integer number, string message, key id)&lt;br /&gt;
    {&lt;br /&gt;
        //if link message is on the correct channel&lt;br /&gt;
        if(number == toAllChannel)&lt;br /&gt;
        {&lt;br /&gt;
            //treat as command input&lt;br /&gt;
            ParseCommand(message);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    } //end of link message&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
} // end default&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_Math_3D.lsl&amp;diff=52672</id>
		<title>TestUnit TestScript Math 3D.lsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_Math_3D.lsl&amp;diff=52672"/>
		<updated>2008-02-04T22:58:20Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Conformance Test]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////            TestUnit_TestScript&lt;br /&gt;
///////             &lt;br /&gt;
///////            Math_3D&lt;br /&gt;
///////&lt;br /&gt;
///////  This is the test script for the 3D math functions.  &lt;br /&gt;
///////      &lt;br /&gt;
///////              &lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////    &lt;br /&gt;
&lt;br /&gt;
//TestUnit_TestScript    .1 -&amp;gt; initial framework  6.23.2007&lt;br /&gt;
//TestUnit_TestScript    .2 -&amp;gt; tested with minor bug fixes  7.2.2007&lt;br /&gt;
&lt;br /&gt;
//Math_3D                .1 -&amp;gt; modified from TestUnit_TestScript base to test 3D math functions  7.3.2007&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//                  Command Protocol&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        CHAT commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  Chat commands will be on the specified broadcastChannel&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
// AddUnitReport - send Report update to Coordinator on the chat broadcastChannel&lt;br /&gt;
// format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        LINK MESSAGE commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  link message commands will be sent out on the toAllChannel, and recieved on the passFailChannel&lt;br /&gt;
//&lt;br /&gt;
//////// INPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  RunTest - activation command to start test&lt;br /&gt;
//  format example -&amp;gt; RunTest&lt;br /&gt;
//&lt;br /&gt;
//  Report - channel and report type&lt;br /&gt;
//  format example -&amp;gt; Report::controlChannel::0::reportType::NORMAL&lt;br /&gt;
//&lt;br /&gt;
//  Reset - rest the scripts &lt;br /&gt;
//  format example -&amp;gt; Reset&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  passFail - status of test sent on passFailChannel&lt;br /&gt;
//  format example -&amp;gt; PASS&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Global Variables&lt;br /&gt;
&lt;br /&gt;
integer toAllChannel = -255;           // general channel - linked message&lt;br /&gt;
integer passFailChannel = -355;        // test scripts channel for cummunicating pass/fail - linked message&lt;br /&gt;
&lt;br /&gt;
integer debug = 0;                     // level of debug message&lt;br /&gt;
integer debugChannel = DEBUG_CHANNEL;  // output channel for debug messages&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
integer llAngleBetweenPASS;            // &lt;br /&gt;
integer llAxes2RotPASS;                //  &lt;br /&gt;
integer llAxisAngle2RotPASS;           //  These are global pass/fail&lt;br /&gt;
integer llEuler2RotPASS;               //  indicators for the various&lt;br /&gt;
integer llRot2EulerPASS;               //  Math 3D functions that are&lt;br /&gt;
integer llRotBetweenPASS;              //  being tested. These variables&lt;br /&gt;
integer llVecDistPASS;                 //  are used in the Run Test &lt;br /&gt;
integer llVecMagPASS;                  //  and Report Functions of this &lt;br /&gt;
integer llVecNormPASS;                 //  script.&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   ParseCommand&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      string message - command to be parsed&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function calls various other functions or sets globals&lt;br /&gt;
//////////                    depending on message string. Allows external command calls.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
ParseCommand(string message)&lt;br /&gt;
{&lt;br /&gt;
    if(debug &amp;gt; 1)llSay(debugChannel, llGetScriptName()+ &amp;quot;-&amp;gt;ParseCommand: &amp;quot; + message);&lt;br /&gt;
        &lt;br /&gt;
    //reset all scripts &lt;br /&gt;
    if(message == &amp;quot;Reset&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        //reset this script &lt;br /&gt;
        llResetScript();                   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //RunTest()&lt;br /&gt;
    else if(message == &amp;quot;RunTest&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        RunTest();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    //Report()&lt;br /&gt;
    //Example format -&amp;gt; Report::broadcastChannel::0::reportType::NORMAL&lt;br /&gt;
    else if( llSubStringIndex(message, &amp;quot;Report&amp;quot;) != -1 )&lt;br /&gt;
    {&lt;br /&gt;
        //parse the string command into a list&lt;br /&gt;
        list reportParameters = llParseString2List( message, [&amp;quot;::&amp;quot;], [&amp;quot;&amp;quot;] );&lt;br /&gt;
        &lt;br /&gt;
        //find the broadcastChannel label and increment by one&lt;br /&gt;
        integer tempIndex = llListFindList( reportParameters, [&amp;quot;controlChannel&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the broadcastChannel from the list with the index just calculated&lt;br /&gt;
        integer controlChannel = llList2Integer( reportParameters , tempIndex);&lt;br /&gt;
        &lt;br /&gt;
        //find the reportType label and increment by one&lt;br /&gt;
        tempIndex = llListFindList( reportParameters, [&amp;quot;reportType&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the reportType from the list with the index just calculated&lt;br /&gt;
        string reportType = llList2String( reportParameters , tempIndex);&lt;br /&gt;
                &lt;br /&gt;
        //call the Report function with new parameters&lt;br /&gt;
        Report( controlChannel, reportType );&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
} //end ParseCommand&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   RunTest&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     link message on passFailChannel test status&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you put the scripts that you want to test&lt;br /&gt;
//////////                  with this unit.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
RunTest()&lt;br /&gt;
{&lt;br /&gt;
     &lt;br /&gt;
     /////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: float llAngleBetween( rotation a, rotation b ); &lt;br /&gt;
     // Returns a float that is the angle between rotation a and b.&lt;br /&gt;
     // • rotation     a     –     start rotation     &lt;br /&gt;
     // • rotation     b     –     end rotation     &lt;br /&gt;
     /////////////////////////////////////////////////////////////////&lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llAngleBetweenPASS = 0;&lt;br /&gt;
     &lt;br /&gt;
     //compare two rotations with no angle in between&lt;br /&gt;
     if( (string)0.0 == (string)llAngleBetween( &amp;lt;0.0, 0.0, 0.0, 1.0&amp;gt;, &amp;lt;0.0, 0.0, 0.0, 1.0&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)2.094395 == (string)llAngleBetween( &amp;lt;1.0, 1.0, 1.0, 1.0&amp;gt;, &amp;lt;0.0, 0.0, 0.0, 1.0&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)2.094395 == (string)llAngleBetween( &amp;lt;0.0, 0.0, 0.0, 1.0&amp;gt;, &amp;lt;1.0, 1.0, 1.0, 1.0&amp;gt; ) )&lt;br /&gt;
     {&lt;br /&gt;
         llAngleBetweenPASS = 1;    &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     /////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: rotation llAxes2Rot( vector fwd, vector left, vector up );&lt;br /&gt;
     // Returns a rotation that is defined by the 3 coordinate axes&lt;br /&gt;
     // • vector     fwd             &lt;br /&gt;
     // • vector     left             &lt;br /&gt;
     // • vector     up&lt;br /&gt;
     /////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llAxes2RotPASS = 0;&lt;br /&gt;
     &lt;br /&gt;
     //test four sets of vector configurations to hardcoded values&lt;br /&gt;
     if( (string)&amp;lt;1.00000, 0.00000, 0.00000, 0.00000&amp;gt; == (string)llAxes2Rot( &amp;lt;0.0, 0.0, 0.0&amp;gt;, &amp;lt;0.0, 0.0, 0.0&amp;gt;, &amp;lt;0.0, 0.0, 0.0&amp;gt;) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;0.00000, -0.35355, 0.35355, 0.70711&amp;gt; == (string)llAxes2Rot( &amp;lt;1.0, 1.0, 1.0&amp;gt;, &amp;lt;0.0, 0.0, 0.0&amp;gt;, &amp;lt;0.0, 0.0, 0.0&amp;gt;) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;0.35355, 0.00000, -0.35355, 0.70711&amp;gt; == (string)llAxes2Rot( &amp;lt;0.0, 0.0, 0.0&amp;gt;, &amp;lt;1.0, 1.0, 1.0&amp;gt;, &amp;lt;0.0, 0.0, 0.0&amp;gt;) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;-0.35355, 0.35355, 0.00000, 0.70711&amp;gt; == (string)llAxes2Rot( &amp;lt;0.0, 0.0, 0.0&amp;gt;, &amp;lt;0.0, 0.0, 0.0&amp;gt;, &amp;lt;1.0, 1.0, 1.0&amp;gt;) )&lt;br /&gt;
     {&lt;br /&gt;
         llAxes2RotPASS = 1; &lt;br /&gt;
     }&lt;br /&gt;
     &lt;br /&gt;
     /////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: rotation llAxisAngle2Rot( vector axis, float angle );&lt;br /&gt;
     // Returns a rotation that is a generated angle about axis&lt;br /&gt;
     // • vector     axis             &lt;br /&gt;
     // • float     angle     –     expressed in radians.     &lt;br /&gt;
     /////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llAxisAngle2RotPASS = 0;&lt;br /&gt;
         &lt;br /&gt;
     //test four sets of configurations to hardcoded values&lt;br /&gt;
     if( (string)&amp;lt;0.00000, 0.00000, 0.00000, 1.00000&amp;gt; == (string)llAxisAngle2Rot( &amp;lt; 0.0, 0.0, 0.0&amp;gt;, 0.0 ) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;0.84147, 0.00000, 0.00000, 0.54030&amp;gt; ==  (string)llAxisAngle2Rot( &amp;lt; 1.0, 0.0, 0.0&amp;gt;, 2.0 ) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;0.27680, 0.27680, 0.27680, 0.87758&amp;gt; == (string)llAxisAngle2Rot( &amp;lt; 1.0, 1.0, 1.0&amp;gt;, 1.0 ) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;0.00000, 0.00000, 0.47943, 0.87758&amp;gt; == (string)llAxisAngle2Rot( &amp;lt; 0.0, 0.0, 1.0&amp;gt;, 1.0 ) )&lt;br /&gt;
     {&lt;br /&gt;
         llAxisAngle2RotPASS = 1; &lt;br /&gt;
     }&lt;br /&gt;
&lt;br /&gt;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     &lt;br /&gt;
     //////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: rotation llEuler2Rot( vector v );&lt;br /&gt;
     // Returns a rotation representation of Euler Angles v.&lt;br /&gt;
     // • vector     v         &lt;br /&gt;
     //////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     &lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llEuler2RotPASS = 0;&lt;br /&gt;
       &lt;br /&gt;
     //test four sets of configurations to hardcoded values&lt;br /&gt;
     if( (string)&amp;lt;0.00000, 0.00000, 0.00000, 1.00000&amp;gt; == (string)llEuler2Rot( &amp;lt; 0.0, 0.0, 0.0&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;0.47943, 0.00000, 0.00000, 0.87758&amp;gt; ==  (string)llEuler2Rot( &amp;lt; 1.0, 0.0, 0.0&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;0.57094, 0.16752, 0.57094, 0.56568&amp;gt; == (string)llEuler2Rot( &amp;lt; 1.0, 1.0, 1.0&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;0.00000, 0.00000, 0.47943, 0.87758&amp;gt; == (string)llEuler2Rot( &amp;lt; 0.0, 0.0, 1.0&amp;gt; ) )&lt;br /&gt;
     {&lt;br /&gt;
         llEuler2RotPASS = 1; &lt;br /&gt;
     }&lt;br /&gt;
  &lt;br /&gt;
       ///////////////////////////////////////////////////////////////////////////////////    &lt;br /&gt;
       // Function: vector llRot2Euler( rotation quat );&lt;br /&gt;
       // Returns a vector that is the Euler representation (roll, pitch, yaw) of quat.&lt;br /&gt;
       // • rotation     quat     –     Any valid rotation     &lt;br /&gt;
       ///////////////////////////////////////////////////////////////////////////////////    &lt;br /&gt;
     &lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llRot2EulerPASS = 0;&lt;br /&gt;
       &lt;br /&gt;
     //test four sets of configurations to hardcoded values&lt;br /&gt;
     if( (string)&amp;lt;-0.00000, 0.00000, -0.00000&amp;gt; == (string)llRot2Euler( &amp;lt;0.00000, 0.00000, 0.00000, 1.00000&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;1.57574, 0.11067, -0.08922&amp;gt; ==  (string)llRot2Euler( &amp;lt;1.00000, 0.10000, 0.01100, 1.00000&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;-1.10715, 0.72973, 2.03444&amp;gt; == (string)llRot2Euler( &amp;lt;0.00000, 1.00000, 1.00000, 1.00000&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;0.00000, 1.57080, 1.57080&amp;gt; == (string)llRot2Euler( &amp;lt;1.00000, 1.00000, 1.00000, 1.00000&amp;gt; ) )&lt;br /&gt;
     {&lt;br /&gt;
         llRot2EulerPASS = 1; &lt;br /&gt;
     }     &lt;br /&gt;
   &lt;br /&gt;
 &lt;br /&gt;
     /////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: rotation llRotBetween( vector start, vector end );&lt;br /&gt;
     // Returns a rotation that is the rotation between start to end&lt;br /&gt;
     // • vector     start             &lt;br /&gt;
     // • vector     end&lt;br /&gt;
     /////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     &lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llRotBetweenPASS = 0;&lt;br /&gt;
       &lt;br /&gt;
     //test four sets of configurations to hardcoded values&lt;br /&gt;
     if( (string)&amp;lt;0.00000, 0.00000, 0.00000, 1.00000&amp;gt; == (string)llRotBetween( &amp;lt; 0.0, 0.0, 0.0&amp;gt;, &amp;lt; 0.0, 0.0, 0.0&amp;gt; ) &amp;amp;&lt;br /&gt;
			(string)&amp;lt;0.00000, 0.03531, -0.70622, 0.70711&amp;gt; ==  (string)llRotBetween( &amp;lt; -10.0, 0.0, 0.0&amp;gt;, &amp;lt; 0.0, 10.0, 0.5&amp;gt; ) &amp;amp;&lt;br /&gt;
			(string)&amp;lt;0.62796, 0.62796, 0.00000, 0.45970&amp;gt; == (string)llRotBetween( &amp;lt; 10.0, -10.0, 10.0&amp;gt;, &amp;lt; 0.0, 0.0, -1.0&amp;gt; ) &amp;amp;&lt;br /&gt;
			(string)&amp;lt;0.00000, -0.99969, 0.00000, 0.02498&amp;gt; == (string)llRotBetween( &amp;lt; 0.0, 0.0, -10.0&amp;gt;, &amp;lt; 0.5, 0.0, 10.0&amp;gt; ) )&lt;br /&gt;
     {&lt;br /&gt;
         llRotBetweenPASS = 1; &lt;br /&gt;
     }     &lt;br /&gt;
      &lt;br /&gt;
     /////////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: float llVecDist( vector vec_a, vector vec_b );&lt;br /&gt;
     // Returns a float that is the distance between vec_a and vec_b (llVecMag(vec_a - vec_b)).&lt;br /&gt;
     // • vector     vec_a     –     Any valid vector     &lt;br /&gt;
     // • vector     vec_b     –     Any valid vector&lt;br /&gt;
     //////////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
      &lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llVecDistPASS = 0;&lt;br /&gt;
       &lt;br /&gt;
     //test four sets of configurations to hardcoded values&lt;br /&gt;
     if( (string)0.0 == (string)llVecDist( &amp;lt; 0.0, 0.0, 0.0&amp;gt;, &amp;lt; 0.0, 0.0, 0.0&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)1.0 ==  (string)llVecDist( &amp;lt; 1.0, 0.0, 0.0&amp;gt;, &amp;lt; 0.0, 0.0, 0.0&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)1.732051 == (string)llVecDist( &amp;lt; 1.0, 1.0, 1.0&amp;gt;, &amp;lt; 0.0, 0.0, 0.0&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)1.0 == (string)llVecDist( &amp;lt; 0.0, 0.0, -1.0&amp;gt;, &amp;lt; 0.0, 0.0, 0.0&amp;gt; ) )&lt;br /&gt;
     {&lt;br /&gt;
         llVecDistPASS = 1; &lt;br /&gt;
     }     &lt;br /&gt;
       &lt;br /&gt;
    &lt;br /&gt;
     //////////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: float llVecMag( vector vec );&lt;br /&gt;
     // Returns a float that is the magnitude of the vector (the distance from vec to &amp;lt;0.0, 0.0, 0.0&amp;gt;).&lt;br /&gt;
     // • vector     vec             &lt;br /&gt;
     //////////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     &lt;br /&gt;
     &lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llVecMagPASS = 0;&lt;br /&gt;
       &lt;br /&gt;
     //test four sets of configurations to hardcoded values&lt;br /&gt;
     if( (string)0.0 == (string)llVecMag( &amp;lt; 0.0, 0.0, 0.0&amp;gt;) &amp;amp;&lt;br /&gt;
     		(string)1.0 ==  (string)llVecMag( &amp;lt; 1.0, 0.0, 0.0&amp;gt;) &amp;amp;&lt;br /&gt;
     		(string)1.732051 == (string)llVecMag( &amp;lt; 1.0, 1.0, 1.0&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)1.414214 == (string)llVecMag( &amp;lt; 1.0, 0.0, -1.0&amp;gt; ) )&lt;br /&gt;
     {&lt;br /&gt;
         llVecMagPASS = 1; &lt;br /&gt;
     }     &lt;br /&gt;
  &lt;br /&gt;
    &lt;br /&gt;
     ///////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
     // Function: vector llVecNorm( vector vec );&lt;br /&gt;
     // Returns a vector that is the normal of the vector (vec / llVecMag(vec)).&lt;br /&gt;
     // • vector     vec     –     Any valid vector     &lt;br /&gt;
     ///////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
    //initialize a pass variable to TRUE &lt;br /&gt;
    llVecNormPASS = 0;&lt;br /&gt;
       &lt;br /&gt;
     //test four sets of configurations to hardcoded values&lt;br /&gt;
     if( (string)&amp;lt; 0.0, 0.0, 0.0&amp;gt; == (string)llVecNorm( &amp;lt; 0.0, 0.0, 0.0&amp;gt;) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt; 1.0, 0.0, 0.0&amp;gt; ==  (string)llVecNorm( &amp;lt; 1.0, 0.0, 0.0&amp;gt;) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;0.57735, 0.57735, 0.57735&amp;gt; == (string)llVecNorm( &amp;lt; 1.0, 1.0, 1.0&amp;gt; ) &amp;amp;&lt;br /&gt;
     		(string)&amp;lt;0.70711, 0.00000, -0.70711&amp;gt; == (string)llVecNorm( &amp;lt; 1.0, 0.0, -1.0&amp;gt; ) )&lt;br /&gt;
     {&lt;br /&gt;
         llVecNormPASS = 1; &lt;br /&gt;
     }         &lt;br /&gt;
   &lt;br /&gt;
    &lt;br /&gt;
     //multiple all of the individual pass variables together to check for any failures.&lt;br /&gt;
     integer pass = llAngleBetweenPASS *&lt;br /&gt;
     llAxes2RotPASS *&lt;br /&gt;
     llAxisAngle2RotPASS *&lt;br /&gt;
     llEuler2RotPASS *&lt;br /&gt;
     llRot2EulerPASS *&lt;br /&gt;
     llRotBetweenPASS *&lt;br /&gt;
     llVecDistPASS *&lt;br /&gt;
     llVecMagPASS *&lt;br /&gt;
     llVecNormPASS;&lt;br /&gt;
     &lt;br /&gt;
&lt;br /&gt;
     &lt;br /&gt;
     // if all of the individual &lt;br /&gt;
     if( pass == 1)&lt;br /&gt;
     {&lt;br /&gt;
       llMessageLinked(LINK_SET, passFailChannel, &amp;quot;PASS&amp;quot;, NULL_KEY);&lt;br /&gt;
     }&lt;br /&gt;
     else&lt;br /&gt;
     {&lt;br /&gt;
       llMessageLinked(LINK_SET, passFailChannel, &amp;quot;FAIL&amp;quot;, NULL_KEY);&lt;br /&gt;
     }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Report&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      broadcastChannel - chat channel to send report&lt;br /&gt;
//////////                  reportType - determines length and content of report type&lt;br /&gt;
//////////                                         -&amp;gt; NORMAL - failures and summary information&lt;br /&gt;
//////////                                         -&amp;gt; QUITE - summary information only&lt;br /&gt;
//////////                                         -&amp;gt; VERBOSE - everything&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     llSay on broadcastChannel &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you design the three level of reports&lt;br /&gt;
//////////                  avaliable upon request by the Coordinator&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Report( integer controlChannel, string reportType )&lt;br /&gt;
{&lt;br /&gt;
    //this string will be sent out reguardless of reporting mode&lt;br /&gt;
    string reportString;&lt;br /&gt;
    &lt;br /&gt;
    // Initialize with FAIL&lt;br /&gt;
    string llAngleBetweenPASSstring = &amp;quot;FAIL&amp;quot;;            &lt;br /&gt;
    string llAxes2RotPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llAxisAngle2RotPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llEuler2RotPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llRot2EulerPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llRotBetweenPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llVecDistPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llVecMagPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    string llVecNormPASSstring = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    //translate integer conditional into text string for the report. &lt;br /&gt;
    if ( llAngleBetweenPASS )&lt;br /&gt;
    {&lt;br /&gt;
          llAngleBetweenPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llAxes2RotPASS )&lt;br /&gt;
    {&lt;br /&gt;
          llAxes2RotPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llAxisAngle2RotPASS )&lt;br /&gt;
    {&lt;br /&gt;
        llAxisAngle2RotPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llEuler2RotPASS)&lt;br /&gt;
    {&lt;br /&gt;
          llEuler2RotPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llRot2EulerPASS )&lt;br /&gt;
    {&lt;br /&gt;
          llRot2EulerPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llRotBetweenPASS )&lt;br /&gt;
    {&lt;br /&gt;
          llRotBetweenPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llVecDistPASS )&lt;br /&gt;
    {&lt;br /&gt;
          llVecDistPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llVecMagPASS )&lt;br /&gt;
    {&lt;br /&gt;
          llVecMagPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    if ( llVecNormPASS )&lt;br /&gt;
    {&lt;br /&gt;
          llVecNormPASSstring = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //Normal - moderate level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;NORMAL&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
      reportString = &amp;quot;Function: float llAngleBetween( rotation a, rotation b ) -&amp;gt; &amp;quot; &lt;br /&gt;
                                                + llAngleBetweenPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: rotation llAxes2Rot( vector fwd, vector left, vector up) -&amp;gt;&amp;quot; &lt;br /&gt;
                                                + llAxes2RotPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: rotation llAxisAngle2Rot( vector axis, float angle ) -&amp;gt; &amp;quot; &lt;br /&gt;
                                                + llAxisAngle2RotPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: rotation llEuler2Rot( vector v ) -&amp;gt; &amp;quot; &lt;br /&gt;
                                                + llEuler2RotPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: vector llRot2Euler( rotation quat ) -&amp;gt; &amp;quot; &lt;br /&gt;
                                                + llRot2EulerPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: rotation llRotBetween( vector start, vector end ) -&amp;gt; &amp;quot;&lt;br /&gt;
                                                + llRotBetweenPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: float llVecDist( vector vec_a, vector vec_b ) -&amp;gt; &amp;quot; &lt;br /&gt;
                                                + llVecDistPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: float llVecMag( vector vec ) -&amp;gt; &amp;quot; &lt;br /&gt;
                                                + llVecMagPASSstring + &amp;quot;\n&amp;quot;&lt;br /&gt;
                   + &amp;quot;Function: vector llVecNorm( vector vec ) -&amp;gt; &amp;quot; &lt;br /&gt;
                                                + llVecNormPASSstring + &amp;quot;\n&amp;quot;;&lt;br /&gt;
       &lt;br /&gt;
    } // end normal  &lt;br /&gt;
&lt;br /&gt;
    //VERBOSE - highest level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;VERBOSE&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
        reportString = &amp;quot;/////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: float llAngleBetween( rotation a, rotation b ) + &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a float that is the angle between rotation a and b.&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • rotation     a     –     start rotation     &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • rotation     b     –     end rotation     &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llAngleBetweenPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				     &lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: rotation llAxes2Rot( vector fwd, vector left, vector up ) +&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a rotation that is defined by the 3 coordinate axes&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • vector     fwd             &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • vector     left             &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • vector     up&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llAxes2RotPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				&lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: rotation llAxisAngle2Rot( vector axis, float angle );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a rotation that is a generated angle about axis&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • vector     axis             &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • float     angle     –     expressed in radians.     &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llAxisAngle2RotPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				     &lt;br /&gt;
				&amp;quot;//////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: rotation llEuler2Rot( vector v );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a rotation representation of Euler Angles v.&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • vector     v         &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;//////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llEuler2RotPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				     &lt;br /&gt;
				&amp;quot;///////////////////////////////////////////////////////////////////////////////////  &amp;quot; + &amp;quot;\n&amp;quot; +  &lt;br /&gt;
				&amp;quot;// Function: vector llRot2Euler( rotation quat );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a vector that is the Euler representation (roll, pitch, yaw) of quat.&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • rotation     quat     –     Any valid rotation     &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;///////////////////////////////////////////////////////////////////////////////////  &amp;quot; + &amp;quot;\n&amp;quot; +  &lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llRot2EulerPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				     &lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: rotation llRotBetween( vector start, vector end );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a rotation that is the rotation between start to end&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • vector     start             &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • vector     end&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llRotBetweenPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				     &lt;br /&gt;
				&amp;quot;/////////////////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: float llVecDist( vector vec_a, vector vec_b );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a float that is the distance between vec_a and vec_b (llVecMag(vec_a - vec_b)).&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • vector     vec_a     –     Any valid vector     &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • vector     vec_b     –     Any valid vector&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;//////////////////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llVecDistPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				  &lt;br /&gt;
				&amp;quot;///////////////////////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: float llVecMag( vector vec );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a float that is the magnitude of the vector (the distance from vec to &amp;lt;0.0, 0.0, 0.0&amp;gt;).&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • vector     vec             &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;///////////////////////////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llVecMagPASSstring + &amp;quot;\n\n&amp;quot; +&lt;br /&gt;
				     &lt;br /&gt;
				&amp;quot;///////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Function: vector llVecNorm( vector vec );&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// Returns a vector that is the normal of the vector (vec / llVecMag(vec)).&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;// • vector     vec     –     Any valid vector     &amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;///////////////////////////////////////////////////////////////////////////////&amp;quot; + &amp;quot;\n&amp;quot; +&lt;br /&gt;
				&amp;quot;PASS/FAIL -&amp;gt; &amp;quot; + llVecNormPASSstring + &amp;quot;\n\n&amp;quot;;&lt;br /&gt;
       &lt;br /&gt;
  }// end verbose&lt;br /&gt;
    &lt;br /&gt;
    //AddUnitReport()&lt;br /&gt;
    //send to Coordinator on the broadcastChannel the selected report&lt;br /&gt;
    //format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
    llSay( controlChannel, &amp;quot;AddUnitReport::unitKey::&amp;quot; + (string)llGetKey() + &amp;quot;::Report::&amp;quot; + reportString);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Initialize&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function initializes any variables or functions necessary&lt;br /&gt;
//////////                  to get us started&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Initialize()&lt;br /&gt;
{&lt;br /&gt;
   //why&lt;br /&gt;
   llSetText( &amp;quot;Math 3D&amp;quot;, &amp;lt;255,255,255&amp;gt;, 1);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE//&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                          DEFAULT STATE                                            //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  State Entry of default state                     //&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
   state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
////////////////////////////////////////////////////////&lt;br /&gt;
//  On Rez of default state                           //&lt;br /&gt;
////////////////////////////////////////////////////////    &lt;br /&gt;
    on_rez(integer start_param)&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  Link Message of default state                    //&lt;br /&gt;
///////////////////////////////////////////////////////   &lt;br /&gt;
    link_message(integer sender_number, integer number, string message, key id)&lt;br /&gt;
    {&lt;br /&gt;
        //if link message is on the correct channel&lt;br /&gt;
        if(number == toAllChannel)&lt;br /&gt;
        {&lt;br /&gt;
            //treat as command input&lt;br /&gt;
            ParseCommand(message);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    } //end of link message&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
} // end default&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_DataServer_Notecard.lsl&amp;diff=52671</id>
		<title>TestUnit TestScript DataServer Notecard.lsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_DataServer_Notecard.lsl&amp;diff=52671"/>
		<updated>2008-02-04T22:57:51Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Conformance Test]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////            TestUnit_TestScript&lt;br /&gt;
///////             &lt;br /&gt;
///////       &lt;br /&gt;
///////&lt;br /&gt;
///////  This is the test script for the notecard data server function &lt;br /&gt;
///////      &lt;br /&gt;
///////              &lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////    &lt;br /&gt;
&lt;br /&gt;
//TestUnit_TestScript    .1 -&amp;gt; initial framework  6.23.2007&lt;br /&gt;
//TestUnit_TestScript    .2 -&amp;gt; tested with minor bug fixes  7.2.2007&lt;br /&gt;
&lt;br /&gt;
//DataServer_Notecard      .1 -&amp;gt; modified from TestUnit_TestScript base to test notecard functions  7.6.2007&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//                  Command Protocol&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        CHAT commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  Chat commands will be on the specified broadcastChannel&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
// AddUnitReport - send Report update to Coordinator on the chat broadcastChannel&lt;br /&gt;
// format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        LINK MESSAGE commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  link message commands will be sent out on the toAllChannel, and recieved on the passFailChannel&lt;br /&gt;
//&lt;br /&gt;
//////// INPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  RunTest - activation command to start test&lt;br /&gt;
//  format example -&amp;gt; RunTest&lt;br /&gt;
//&lt;br /&gt;
//  Report - channel and report type&lt;br /&gt;
//  format example -&amp;gt; Report::controlChannel::0::reportType::NORMAL&lt;br /&gt;
//&lt;br /&gt;
//  Reset - rest the scripts &lt;br /&gt;
//  format example -&amp;gt; Reset&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  passFail - status of test sent on passFailChannel&lt;br /&gt;
//  format example -&amp;gt; PASS&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Global Variables&lt;br /&gt;
&lt;br /&gt;
integer toAllChannel = -255;                                      // general channel - linked message&lt;br /&gt;
integer passFailChannel = -355;                                   // test scripts channel for cummunicating pass/fail - linked message&lt;br /&gt;
&lt;br /&gt;
integer debug = 0;                                                // level of debug message&lt;br /&gt;
integer debugChannel = DEBUG_CHANNEL;                             // output channel for debug messages&lt;br /&gt;
&lt;br /&gt;
string lineOne = &amp;quot;DataServerNotecardTest_nc&amp;quot;;                     // string message used to test the notecard function&lt;br /&gt;
string lineTwo = &amp;quot;The is the second line of the notecard&amp;quot;;        // string message used to test the notecard function&lt;br /&gt;
string lineThree = &amp;quot;This must be the last line of the notecard&amp;quot;;  // string message used to test the notecard function&lt;br /&gt;
&lt;br /&gt;
string lineOne_nc;                                                // string message used to test the notecard function&lt;br /&gt;
string lineTwo_nc;                                                // string message used to test the notecard function&lt;br /&gt;
string lineThree_nc;                                              // string message used to test the notecard function&lt;br /&gt;
&lt;br /&gt;
integer notecardLines;                                            //&lt;br /&gt;
key notecardRequestKey;                                           // notecard globals &lt;br /&gt;
key notecardLineRequest;                                          // &lt;br /&gt;
integer currentNoteLine;                                          //&lt;br /&gt;
&lt;br /&gt;
string passIndication;                                            // status variable for the pass/fail of the test&lt;br /&gt;
        &lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   ParseCommand&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      string message - command to be parsed&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function calls various other functions or sets globals&lt;br /&gt;
//////////                    depending on message string. Allows external command calls.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
ParseCommand(string message)&lt;br /&gt;
{&lt;br /&gt;
    if(debug &amp;gt; 1)llSay(debugChannel, llGetScriptName()+ &amp;quot;-&amp;gt;ParseCommand: &amp;quot; + message);&lt;br /&gt;
        &lt;br /&gt;
    //reset all scripts &lt;br /&gt;
    if(message == &amp;quot;reset&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        //reset this script &lt;br /&gt;
        llResetScript();                   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //RunTest()&lt;br /&gt;
    else if(message == &amp;quot;RunTest&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        RunTest();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    //Report()&lt;br /&gt;
    //Example format -&amp;gt; Report::broadcastChannel::0::reportType::NORMAL&lt;br /&gt;
    else if( llSubStringIndex(message, &amp;quot;Report&amp;quot;) != -1 )&lt;br /&gt;
    {&lt;br /&gt;
        //parse the string command into a list&lt;br /&gt;
        list reportParameters = llParseString2List( message, [&amp;quot;::&amp;quot;], [&amp;quot;&amp;quot;] );&lt;br /&gt;
        &lt;br /&gt;
        //find the broadcastChannel label and increment by one&lt;br /&gt;
        integer tempIndex = llListFindList( reportParameters, [&amp;quot;controlChannel&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the broadcastChannel from the list with the index just calculated&lt;br /&gt;
        integer controlChannel = llList2Integer( reportParameters , tempIndex);&lt;br /&gt;
        &lt;br /&gt;
        //find the reportType label and increment by one&lt;br /&gt;
        tempIndex = llListFindList( reportParameters, [&amp;quot;reportType&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the reportType from the list with the index just calculated&lt;br /&gt;
        string reportType = llList2String( reportParameters , tempIndex);&lt;br /&gt;
                &lt;br /&gt;
        //call the Report function with new parameters&lt;br /&gt;
        Report( controlChannel, reportType );&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
} //end ParseCommand&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   RunTest&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     link message on passFailChannel test status&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you put the scripts that you want to test&lt;br /&gt;
//////////                  with this unit.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
RunTest()&lt;br /&gt;
{&lt;br /&gt;
        //initiate data server call to begin reading notecard&lt;br /&gt;
        //the first line of the notecard is also the name of the notecard&lt;br /&gt;
        notecardRequestKey = llGetNumberOfNotecardLines(lineOne);&lt;br /&gt;
     &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Report&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      broadcastChannel - chat channel to send report&lt;br /&gt;
//////////                  reportType - determines length and content of report type&lt;br /&gt;
//////////                                         -&amp;gt; NORMAL - failures and summary information&lt;br /&gt;
//////////                                         -&amp;gt; QUITE - summary information only&lt;br /&gt;
//////////                                         -&amp;gt; VERBOSE - everything&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     llSay on broadcastChannel &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you design the three level of reports&lt;br /&gt;
//////////                  avaliable upon request by the Coordinator&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Report( integer broadcastChannel, string reportType )&lt;br /&gt;
{&lt;br /&gt;
    string reportString;&lt;br /&gt;
&lt;br /&gt;
    //Normal - moderate level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;NORMAL&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
        reportString += &amp;quot;notecardLines: &amp;quot; + (string)notecardLines + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;notecardRequestKey: &amp;quot; + (string)notecardRequestKey + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;notecardLineRequest: &amp;quot; + (string)notecardLineRequest + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;currentNoteLine: &amp;quot; + (string)currentNoteLine + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        &lt;br /&gt;
        reportString += &amp;quot;lineOne_nc: &amp;quot; + lineOne_nc + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;lineTwo_nc: &amp;quot; + lineTwo_nc + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;lineThree_nc: &amp;quot; + lineThree_nc + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //QUIET - shortest level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;QUIET&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
        reportString += &amp;quot;lineOne_nc: &amp;quot; + lineOne_nc + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;lineTwo_nc: &amp;quot; + lineTwo_nc + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;lineThree_nc: &amp;quot; + lineThree_nc + &amp;quot;\n&amp;quot;;  &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //VERBOSE - highest level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;VERBOSE&amp;quot; )&lt;br /&gt;
    {        &lt;br /&gt;
        reportString += &amp;quot;lineOne: &amp;quot; + lineOne + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;lineOne_nc: &amp;quot; + lineOne_nc + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;lineTwo: &amp;quot; + lineTwo + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;lineTwo_nc: &amp;quot; + lineTwo_nc + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;lineThree: &amp;quot; + lineThree + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;lineThree_nc: &amp;quot; + lineThree_nc + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;notecardLines: &amp;quot; + (string)notecardLines + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;notecardRequestKey: &amp;quot; + (string)notecardRequestKey + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;notecardLineRequest: &amp;quot; + (string)notecardLineRequest + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;currentNoteLine: &amp;quot; + (string)currentNoteLine + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //AddUnitReport()&lt;br /&gt;
    //send to Coordinator on the broadcastChannel the selected report&lt;br /&gt;
    //format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
    llSay( broadcastChannel, &amp;quot;AddUnitReport::unitKey::&amp;quot; + (string)llGetKey() + &amp;quot;::Report::&amp;quot; + reportString);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
       &lt;br /&gt;
                 &lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Initialize&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function initializes any variables or functions necessary&lt;br /&gt;
//////////                  to get us started&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Initialize()&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
   llSetText( &amp;quot;DataServer_Notecard&amp;quot;, &amp;lt;255,255,255&amp;gt;, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE//&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                          DEFAULT STATE                                            //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  State Entry of default state                     //&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
   state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
////////////////////////////////////////////////////////&lt;br /&gt;
//  On Rez of default state                           //&lt;br /&gt;
////////////////////////////////////////////////////////    &lt;br /&gt;
    on_rez(integer start_param)&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  Link Message of default state                    //&lt;br /&gt;
///////////////////////////////////////////////////////   &lt;br /&gt;
    link_message(integer sender_number, integer number, string message, key id)&lt;br /&gt;
    {&lt;br /&gt;
        //if link message is on the correct channel&lt;br /&gt;
        if(number == toAllChannel)&lt;br /&gt;
        {&lt;br /&gt;
            //treat as command input&lt;br /&gt;
            ParseCommand(message);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    } //end of link message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  data server of default                           //&lt;br /&gt;
///////////////////////////////////////////////////////   &lt;br /&gt;
    dataserver(key queryid, string data)&lt;br /&gt;
    {&lt;br /&gt;
        if(debug &amp;gt; 1)llSay(debugChannel, llGetScriptName()+ &amp;quot;-&amp;gt;DataServer: &amp;quot; + data);&lt;br /&gt;
        &lt;br /&gt;
        if(queryid == notecardRequestKey) // line number request&lt;br /&gt;
        {&lt;br /&gt;
            //set the number of lines in the notecard&lt;br /&gt;
            notecardLines = (integer)data;&lt;br /&gt;
            //move the pointer to zero&lt;br /&gt;
            currentNoteLine = 0;&lt;br /&gt;
            //the name of the notecard is stored in the lineOne string variable&lt;br /&gt;
            notecardLineRequest = llGetNotecardLine(lineOne, currentNoteLine);&lt;br /&gt;
            &lt;br /&gt;
            //since linenumber is the first&lt;br /&gt;
            //set pass&lt;br /&gt;
            passIndication = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
            &lt;br /&gt;
        } //end line number request&lt;br /&gt;
        &lt;br /&gt;
        if(queryid == notecardLineRequest) //reading a line from the notecard&lt;br /&gt;
        {&lt;br /&gt;
            if( currentNoteLine == 0 )&lt;br /&gt;
            {&lt;br /&gt;
                if( data != lineOne)&lt;br /&gt;
                {&lt;br /&gt;
                    passIndication = &amp;quot;FAIL&amp;quot;;    &lt;br /&gt;
                }&lt;br /&gt;
                lineOne_nc = data;&lt;br /&gt;
            }&lt;br /&gt;
            else if ( currentNoteLine == 1 )&lt;br /&gt;
            {&lt;br /&gt;
                if( data != lineTwo)&lt;br /&gt;
                {&lt;br /&gt;
                    passIndication = &amp;quot;FAIL&amp;quot;;    &lt;br /&gt;
                }&lt;br /&gt;
                lineTwo_nc = data;&lt;br /&gt;
            }&lt;br /&gt;
            else if ( currentNoteLine == 2 )&lt;br /&gt;
            {&lt;br /&gt;
                if( data != lineThree)&lt;br /&gt;
                {&lt;br /&gt;
                    passIndication = &amp;quot;FAIL&amp;quot;;    &lt;br /&gt;
                }&lt;br /&gt;
                lineThree_nc = data;&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            &lt;br /&gt;
            //if additional lines on the notecard&lt;br /&gt;
            if(currentNoteLine &amp;lt; notecardLines - 1)&lt;br /&gt;
            {&lt;br /&gt;
                currentNoteLine += 1;&lt;br /&gt;
                //initiate another line request from the dataserver&lt;br /&gt;
                notecardLineRequest = llGetNotecardLine(lineOne, currentNoteLine);&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                // Done testing&lt;br /&gt;
            &lt;br /&gt;
                //One of the following messages needs to be sent at the end of this function&lt;br /&gt;
                //each time that it is run&lt;br /&gt;
                //&lt;br /&gt;
                // llMessageLinked(LINK_SET, passFailChannel, &amp;quot;PASS&amp;quot;, NULL_KEY);&lt;br /&gt;
                // llMessageLinked(LINK_SET, passFailChannel, &amp;quot;FAIL&amp;quot;, NULL_KEY);&lt;br /&gt;
                llMessageLinked(LINK_SET, passFailChannel, passIndication, NULL_KEY);&lt;br /&gt;
                &lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
        } //end line request&lt;br /&gt;
    } //end data server&lt;br /&gt;
    &lt;br /&gt;
          &lt;br /&gt;
&lt;br /&gt;
} // end default&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_Communication_Rpc.lsl&amp;diff=52670</id>
		<title>TestUnit TestScript Communication Rpc.lsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_Communication_Rpc.lsl&amp;diff=52670"/>
		<updated>2008-02-04T22:57:37Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Conformance Test]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////            TestUnit_TestScript&lt;br /&gt;
///////             &lt;br /&gt;
///////       &lt;br /&gt;
///////&lt;br /&gt;
///////  This is the test script for the XML-RPC communication function &lt;br /&gt;
///////      &lt;br /&gt;
///////              &lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////    &lt;br /&gt;
&lt;br /&gt;
//TestUnit_TestScript    .1 -&amp;gt; initial framework  6.23.2007&lt;br /&gt;
//TestUnit_TestScript    .2 -&amp;gt; tested with minor bug fixes  7.2.2007&lt;br /&gt;
&lt;br /&gt;
//Communication_Rpc      .1 -&amp;gt; modified from TestUnit_TestScript base to test rpc functions  7.6.2007&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//                  Command Protocol&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        CHAT commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  Chat commands will be on the specified broadcastChannel&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
// AddUnitReport - send Report update to Coordinator on the chat broadcastChannel&lt;br /&gt;
// format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        LINK MESSAGE commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  link message commands will be sent out on the toAllChannel, and recieved on the passFailChannel&lt;br /&gt;
//&lt;br /&gt;
//////// INPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  RunTest - activation command to start test&lt;br /&gt;
//  format example -&amp;gt; RunTest&lt;br /&gt;
//&lt;br /&gt;
//  Report - channel and report type&lt;br /&gt;
//  format example -&amp;gt; Report::controlChannel::0::reportType::NORMAL&lt;br /&gt;
//&lt;br /&gt;
//  Reset - rest the scripts &lt;br /&gt;
//  format example -&amp;gt; Reset&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  passFail - status of test sent on passFailChannel&lt;br /&gt;
//  format example -&amp;gt; PASS&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Global Variables&lt;br /&gt;
&lt;br /&gt;
integer toAllChannel = -255;                                      // general channel - linked message&lt;br /&gt;
integer passFailChannel = -355;                                   // test scripts channel for cummunicating pass/fail - linked message&lt;br /&gt;
&lt;br /&gt;
integer debug = 2;                                                // level of debug message&lt;br /&gt;
integer debugChannel = DEBUG_CHANNEL;                             // output channel for debug messages&lt;br /&gt;
&lt;br /&gt;
key HTTP_CONTROL;                                                 // HTTP Handler &lt;br /&gt;
string HTTP_URL = &amp;quot;http://www.i3dnow.com/LSLTest_Rpc.php&amp;quot;;        // url for the RPC test&lt;br /&gt;
&lt;br /&gt;
string http_body;                                                 // temp storage for the http response&lt;br /&gt;
&lt;br /&gt;
key gChannel;                                                     // XML-RPC channel&lt;br /&gt;
list remoteInfo;                                                  // a list of the parameters of the remote_data listener&lt;br /&gt;
&lt;br /&gt;
string stringMessage = &amp;quot;Myvoiceismypassport&amp;quot;;                     // string message used to test the XML-RPC&lt;br /&gt;
integer intMessage = 42;                                          // integer message used to test the XML-RPC&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   ParseCommand&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      string message - command to be parsed&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function calls various other functions or sets globals&lt;br /&gt;
//////////                    depending on message string. Allows external command calls.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
ParseCommand(string message)&lt;br /&gt;
{&lt;br /&gt;
    if(debug &amp;gt; 1)llSay(debugChannel, llGetScriptName()+ &amp;quot;-&amp;gt;ParseCommand: &amp;quot; + message);&lt;br /&gt;
        &lt;br /&gt;
    //reset all scripts &lt;br /&gt;
    if(message == &amp;quot;reset&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        //reset this script &lt;br /&gt;
        llResetScript();                   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //RunTest()&lt;br /&gt;
    else if(message == &amp;quot;RunTest&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        RunTest();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    //Report()&lt;br /&gt;
    //Example format -&amp;gt; Report::broadcastChannel::0::reportType::NORMAL&lt;br /&gt;
    else if( llSubStringIndex(message, &amp;quot;Report&amp;quot;) != -1 )&lt;br /&gt;
    {&lt;br /&gt;
        //parse the string command into a list&lt;br /&gt;
        list reportParameters = llParseString2List( message, [&amp;quot;::&amp;quot;], [&amp;quot;&amp;quot;] );&lt;br /&gt;
        &lt;br /&gt;
        //find the broadcastChannel label and increment by one&lt;br /&gt;
        integer tempIndex = llListFindList( reportParameters, [&amp;quot;controlChannel&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the broadcastChannel from the list with the index just calculated&lt;br /&gt;
        integer controlChannel = llList2Integer( reportParameters , tempIndex);&lt;br /&gt;
        &lt;br /&gt;
        //find the reportType label and increment by one&lt;br /&gt;
        tempIndex = llListFindList( reportParameters, [&amp;quot;reportType&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the reportType from the list with the index just calculated&lt;br /&gt;
        string reportType = llList2String( reportParameters , tempIndex);&lt;br /&gt;
                &lt;br /&gt;
        //call the Report function with new parameters&lt;br /&gt;
        Report( controlChannel, reportType );&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
} //end ParseCommand&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   RunTest&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     link message on passFailChannel test status&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you put the scripts that you want to test&lt;br /&gt;
//////////                  with this unit.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
RunTest()&lt;br /&gt;
{&lt;br /&gt;
     // this will raise remote_data event REMOTE_DATA_CHANNEL when created&lt;br /&gt;
     llOpenRemoteDataChannel(); // create an XML-RPC channel&lt;br /&gt;
        &lt;br /&gt;
     &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Report&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      broadcastChannel - chat channel to send report&lt;br /&gt;
//////////                  reportType - determines length and content of report type&lt;br /&gt;
//////////                                         -&amp;gt; NORMAL - failures and summary information&lt;br /&gt;
//////////                                         -&amp;gt; QUITE - summary information only&lt;br /&gt;
//////////                                         -&amp;gt; VERBOSE - everything&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     llSay on broadcastChannel &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you design the three level of reports&lt;br /&gt;
//////////                  avaliable upon request by the Coordinator&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Report( integer broadcastChannel, string reportType )&lt;br /&gt;
{&lt;br /&gt;
    string reportString;&lt;br /&gt;
    &lt;br /&gt;
    //Normal - moderate level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;NORMAL&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
        // format example -&amp;gt; remoteInfo = [ type, channel, message_id, sender, ival, sval ];&lt;br /&gt;
        reportString += &amp;quot;type: &amp;quot; + llList2String( remoteInfo, 0) + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;channel: &amp;quot; + llList2String( remoteInfo, 1)+ &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;message_id: &amp;quot; + llList2String( remoteInfo, 2)+ &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;sender: &amp;quot; + llList2String( remoteInfo, 3)+ &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;ival: &amp;quot; + llList2String( remoteInfo, 4)+ &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;sval: &amp;quot; + llList2String( remoteInfo, 5)+ &amp;quot;\n&amp;quot;;&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //QUITE - shortest level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;QUIET&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
        reportString += &amp;quot;ival: &amp;quot; + llList2String( remoteInfo, 4)+ &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;sval: &amp;quot; + llList2String( remoteInfo, 5)+ &amp;quot;\n&amp;quot;;  &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //VERBOSE - highest level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;VERBOSE&amp;quot; )&lt;br /&gt;
    {        &lt;br /&gt;
        reportString += &amp;quot;http_body: &amp;quot; + http_body + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        &lt;br /&gt;
        reportString += &amp;quot;type: &amp;quot; + llList2String( remoteInfo, 0) + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;channel: &amp;quot; + llList2String( remoteInfo, 1) + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;message_id: &amp;quot; + llList2String( remoteInfo, 2) + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;sender: &amp;quot; + llList2String( remoteInfo, 3) + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;ival_rpc: &amp;quot; + llList2String( remoteInfo, 4) + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;ival: &amp;quot; + (string)intMessage + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;sval_rpc: &amp;quot; + llList2String( remoteInfo, 5) + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;sval: &amp;quot; + stringMessage + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //AddUnitReport()&lt;br /&gt;
    //send to Coordinator on the broadcastChannel the selected report&lt;br /&gt;
    //format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
    llSay( broadcastChannel, &amp;quot;AddUnitReport::unitKey::&amp;quot; + (string)llGetKey() + &amp;quot;::Report::&amp;quot; + reportString);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
       &lt;br /&gt;
                 &lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Initialize&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function initializes any variables or functions necessary&lt;br /&gt;
//////////                  to get us started&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Initialize()&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
   llSetText( &amp;quot;Communication_Rpc&amp;quot; , &amp;lt;255,255,255&amp;gt;, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE//&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                          DEFAULT STATE                                            //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  State Entry of default state                     //&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
   state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
////////////////////////////////////////////////////////&lt;br /&gt;
//  On Rez of default state                           //&lt;br /&gt;
////////////////////////////////////////////////////////    &lt;br /&gt;
    on_rez(integer start_param)&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  Link Message of default state                    //&lt;br /&gt;
///////////////////////////////////////////////////////   &lt;br /&gt;
    link_message(integer sender_number, integer number, string message, key id)&lt;br /&gt;
    {&lt;br /&gt;
        //if link message is on the correct channel&lt;br /&gt;
        if(number == toAllChannel)&lt;br /&gt;
        {&lt;br /&gt;
            //treat as command input&lt;br /&gt;
            ParseCommand(message);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    } //end of link message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  Http Response of default state                   //&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
http_response(key id, integer status, list metadata, string body)&lt;br /&gt;
    {&lt;br /&gt;
        if(debug &amp;gt; 0){llSay(debugChannel, llGetScriptName()+ &amp;quot;:FUNCTION: DEFAULT HTTP&amp;quot;);}&lt;br /&gt;
        if(debug &amp;gt; 0){llSay(debugChannel, body);}&lt;br /&gt;
   &lt;br /&gt;
        //if it was a call to the url&lt;br /&gt;
        if(id == HTTP_CONTROL)&lt;br /&gt;
        {    &lt;br /&gt;
            http_body = body; &lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    } // end http_reponse&lt;br /&gt;
    &lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  Remote Data of default state                     //&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
    remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval)&lt;br /&gt;
    {&lt;br /&gt;
        //if it is the channel creation&lt;br /&gt;
        if (type == REMOTE_DATA_CHANNEL)&lt;br /&gt;
        { &lt;br /&gt;
            // channel created&lt;br /&gt;
            gChannel = channel;&lt;br /&gt;
&lt;br /&gt;
            //initiate a XML-RPC call through the test url&lt;br /&gt;
            HTTP_CONTROL = llHTTPRequest( HTTP_URL + &amp;quot;?channel=&amp;quot; + (string)channel &lt;br /&gt;
                                                   + &amp;quot;&amp;amp;stringMessage=&amp;quot; + stringMessage &lt;br /&gt;
                                                   + &amp;quot;&amp;amp;intMessage=&amp;quot; + (string)intMessage  &lt;br /&gt;
                                                   , [HTTP_METHOD,&amp;quot;POST&amp;quot;],&amp;quot;&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        // if it is data coming in from the test url &lt;br /&gt;
        if (type == REMOTE_DATA_REQUEST)&lt;br /&gt;
        { &lt;br /&gt;
            //set pass indicator&lt;br /&gt;
            string passIndication = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
            &lt;br /&gt;
            remoteInfo = [ type, channel, message_id, sender, ival, sval ];&lt;br /&gt;
            &lt;br /&gt;
            //if the incomming value does not matche the requested string            &lt;br /&gt;
            if(sval != stringMessage )&lt;br /&gt;
            {&lt;br /&gt;
                if(debug &amp;gt; 0){llSay(debugChannel, llGetScriptName()+ &amp;quot;:svalFAIL&amp;quot;);}&lt;br /&gt;
                passIndication = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            //if the incomming value does not match the requested integer&lt;br /&gt;
            if(ival != intMessage)&lt;br /&gt;
            {&lt;br /&gt;
                if(debug &amp;gt; 0){llSay(debugChannel, llGetScriptName()+ &amp;quot;:intFAIL&amp;quot;);}&lt;br /&gt;
                passIndication = &amp;quot;FAIL&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            //One of the following messages needs to be sent at the end of this function&lt;br /&gt;
            //each time that it is run&lt;br /&gt;
            //&lt;br /&gt;
            // llMessageLinked(LINK_SET, passFailChannel, &amp;quot;PASS&amp;quot;, NULL_KEY);&lt;br /&gt;
            // llMessageLinked(LINK_SET, passFailChannel, &amp;quot;FAIL&amp;quot;, NULL_KEY);&lt;br /&gt;
            llMessageLinked(LINK_SET, passFailChannel, passIndication, NULL_KEY);&lt;br /&gt;
            &lt;br /&gt;
        } &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    } // end of remote data&lt;br /&gt;
    &lt;br /&gt;
          &lt;br /&gt;
&lt;br /&gt;
} // end default&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Category:Conformance_Test&amp;diff=52669</id>
		<title>Category:Conformance Test</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Category:Conformance_Test&amp;diff=52669"/>
		<updated>2008-02-04T22:56:24Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These are the unit tests we run for LSL using the [[LSL Test Harness]]. Some of the tests are based on the [[Template:LSL_conformance_test]] while others are free-form. If you want to add new unit tests, prefer using the [[Template:LSL_conformance_test|template]] since it will allow the engineering staff the opportunity to more quickly approve and adopt the test.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Category:Conformance_Test&amp;diff=52668</id>
		<title>Category:Conformance Test</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Category:Conformance_Test&amp;diff=52668"/>
		<updated>2008-02-04T22:54:03Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These are the unit tests we run for LSL using the [[LSL Test Harness]].&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_Communication_Http.lsl&amp;diff=52667</id>
		<title>TestUnit TestScript Communication Http.lsl</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=TestUnit_TestScript_Communication_Http.lsl&amp;diff=52667"/>
		<updated>2008-02-04T22:49:58Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Conformance_Test]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////&lt;br /&gt;
///////            TestUnit_TestScript&lt;br /&gt;
///////             &lt;br /&gt;
///////       &lt;br /&gt;
///////&lt;br /&gt;
///////  This is the test script for the HTTP communication function &lt;br /&gt;
///////      &lt;br /&gt;
///////              &lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////    &lt;br /&gt;
&lt;br /&gt;
//TestUnit_TestScript    .1 -&amp;gt; initial framework  6.23.2007&lt;br /&gt;
//TestUnit_TestScript    .2 -&amp;gt; tested with minor bug fixes  7.2.2007&lt;br /&gt;
&lt;br /&gt;
//Communication_Http     .1 -&amp;gt; modified from TestUnit_TestScript base to test http functions  7.6.2007&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//                  Command Protocol&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        CHAT commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  Chat commands will be on the specified broadcastChannel&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
// AddUnitReport - send Report update to Coordinator on the chat broadcastChannel&lt;br /&gt;
// format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//        LINK MESSAGE commands&lt;br /&gt;
//////////////////////////////////////////////&lt;br /&gt;
//&lt;br /&gt;
//  link message commands will be sent out on the toAllChannel, and recieved on the passFailChannel&lt;br /&gt;
//&lt;br /&gt;
//////// INPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  RunTest - activation command to start test&lt;br /&gt;
//  format example -&amp;gt; RunTest&lt;br /&gt;
//&lt;br /&gt;
//  Report - channel and report type&lt;br /&gt;
//  format example -&amp;gt; Report::controlChannel::0::reportType::NORMAL&lt;br /&gt;
//&lt;br /&gt;
//  Reset - rest the scripts &lt;br /&gt;
//  format example -&amp;gt; Reset&lt;br /&gt;
//&lt;br /&gt;
//////// OUTPUT ///////////&lt;br /&gt;
//&lt;br /&gt;
//  passFail - status of test sent on passFailChannel&lt;br /&gt;
//  format example -&amp;gt; PASS&lt;br /&gt;
//&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Global Variables&lt;br /&gt;
&lt;br /&gt;
integer toAllChannel = -255;                                      // general channel - linked message&lt;br /&gt;
integer passFailChannel = -355;                                   // test scripts channel for cummunicating pass/fail - linked message&lt;br /&gt;
&lt;br /&gt;
integer debug = 0;                                                // level of debug message&lt;br /&gt;
integer debugChannel = DEBUG_CHANNEL;                             // output channel for debug messages&lt;br /&gt;
&lt;br /&gt;
key HTTP_CONTROL;                                                 // HTTP Handler &lt;br /&gt;
string HTTP_URL = &amp;quot;TODO: add your server url here&amp;quot;;               // url for the HTTP test&lt;br /&gt;
&lt;br /&gt;
string http_body;                                                 // temp storage for the http response&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   ParseCommand&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      string message - command to be parsed&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function calls various other functions or sets globals&lt;br /&gt;
//////////                    depending on message string. Allows external command calls.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
ParseCommand(string message)&lt;br /&gt;
{&lt;br /&gt;
    if(debug &amp;gt; 1)llSay(debugChannel, llGetScriptName()+ &amp;quot;-&amp;gt;ParseCommand: &amp;quot; + message);&lt;br /&gt;
        &lt;br /&gt;
    //reset all scripts &lt;br /&gt;
    if(message == &amp;quot;reset&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        //reset this script &lt;br /&gt;
        llResetScript();                   &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //RunTest()&lt;br /&gt;
    else if(message == &amp;quot;RunTest&amp;quot;)&lt;br /&gt;
    {&lt;br /&gt;
        RunTest();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    //Report()&lt;br /&gt;
    //Example format -&amp;gt; Report::broadcastChannel::0::reportType::NORMAL&lt;br /&gt;
    else if( llSubStringIndex(message, &amp;quot;Report&amp;quot;) != -1 )&lt;br /&gt;
    {&lt;br /&gt;
        //parse the string command into a list&lt;br /&gt;
        list reportParameters = llParseString2List( message, [&amp;quot;::&amp;quot;], [&amp;quot;&amp;quot;] );&lt;br /&gt;
        &lt;br /&gt;
        //find the broadcastChannel label and increment by one&lt;br /&gt;
        integer tempIndex = llListFindList( reportParameters, [&amp;quot;controlChannel&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the broadcastChannel from the list with the index just calculated&lt;br /&gt;
        integer controlChannel = llList2Integer( reportParameters , tempIndex);&lt;br /&gt;
        &lt;br /&gt;
        //find the reportType label and increment by one&lt;br /&gt;
        tempIndex = llListFindList( reportParameters, [&amp;quot;reportType&amp;quot;] ) + 1;&lt;br /&gt;
        //pull the reportType from the list with the index just calculated&lt;br /&gt;
        string reportType = llList2String( reportParameters , tempIndex);&lt;br /&gt;
                &lt;br /&gt;
        //call the Report function with new parameters&lt;br /&gt;
        Report( controlChannel, reportType );&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
} //end ParseCommand&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   RunTest&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     link message on passFailChannel test status&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you put the scripts that you want to test&lt;br /&gt;
//////////                  with this unit.&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
RunTest()&lt;br /&gt;
{&lt;br /&gt;
     //initiate a http request&lt;br /&gt;
     HTTP_CONTROL = llHTTPRequest( HTTP_URL, [HTTP_METHOD,&amp;quot;PUT&amp;quot;],&amp;quot;&amp;quot;);&lt;br /&gt;
     &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Report&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      broadcastChannel - chat channel to send report&lt;br /&gt;
//////////                  reportType - determines length and content of report type&lt;br /&gt;
//////////                                         -&amp;gt; NORMAL - failures and summary information&lt;br /&gt;
//////////                                         -&amp;gt; QUITE - summary information only&lt;br /&gt;
//////////                                         -&amp;gt; VERBOSE - everything&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     llSay on broadcastChannel &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is where you design the three level of reports&lt;br /&gt;
//////////                  avaliable upon request by the Coordinator&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Report( integer broadcastChannel, string reportType )&lt;br /&gt;
{&lt;br /&gt;
    string reportString;&lt;br /&gt;
    &lt;br /&gt;
    &lt;br /&gt;
     if(debug &amp;gt; 1)llSay(debugChannel, llGetScriptName()+ &amp;quot;-&amp;gt;Report() type=&amp;quot; + reportType);&lt;br /&gt;
     &lt;br /&gt;
    //Normal - moderate level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;NORMAL&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
        //parse http response to useful list&lt;br /&gt;
        //format example -&amp;gt; ownername::objectname::objectkey::ownerkey::region::location&lt;br /&gt;
        list unitParameters = llParseString2List( http_body , [&amp;quot;::&amp;quot;], [&amp;quot;&amp;quot;]); &lt;br /&gt;
        &lt;br /&gt;
        reportString += &amp;quot;http_ownername: &amp;quot; + llList2String( unitParameters, 0) + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;http_objectname: &amp;quot; + llList2String( unitParameters, 1)+ &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;http_objectkey: &amp;quot; + llList2String( unitParameters, 2)+ &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;http_ownerkey: &amp;quot; + llList2String( unitParameters, 3)+ &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;http_region: &amp;quot; + llList2String( unitParameters, 4)+ &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;http_location: &amp;quot; + llList2String( unitParameters, 5)+ &amp;quot;\n&amp;quot;;&lt;br /&gt;
        &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //QUITE - shortest level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;QUIET&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
        reportString = http_body;  &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //VERBOSE - highest level of reporting&lt;br /&gt;
    if( reportType == &amp;quot;VERBOSE&amp;quot; )&lt;br /&gt;
    {&lt;br /&gt;
        &lt;br /&gt;
        //parse http response to useful list&lt;br /&gt;
        //format example -&amp;gt; ownername::objectname::objectkey::ownerkey::region::location&lt;br /&gt;
        list unitParameters= llParseString2List( http_body, [&amp;quot;::&amp;quot;], [&amp;quot;&amp;quot;]);&lt;br /&gt;
        &lt;br /&gt;
        reportString += &amp;quot;http_body: &amp;quot; + llDumpList2String( unitParameters , &amp;quot;,&amp;quot;) + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;http_ownername: &amp;quot; + llList2String( unitParameters, 0) + &amp;quot; --- ownername: &amp;quot; + llKey2Name( llGetOwner() ) + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;http_objectname: &amp;quot; + llList2String( unitParameters, 1)+ &amp;quot; --- objectname: &amp;quot; + llGetObjectName()  + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;http_objectkey: &amp;quot; + llList2String( unitParameters, 2)+ &amp;quot; --- objectkey: &amp;quot; + (string)llGetKey() + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;http_ownerkey: &amp;quot; + llList2String( unitParameters, 3)+ &amp;quot; --- ownerkey: &amp;quot; + (string)llGetOwner() + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;http_region: &amp;quot; + llList2String( unitParameters, 4)+ &amp;quot; --- region: &amp;quot; + llGetRegionName() + &amp;quot;\n&amp;quot;;&lt;br /&gt;
        reportString += &amp;quot;http_location: &amp;quot; + llList2String( unitParameters, 5)+ &amp;quot; --- location: &amp;quot; + (string)llGetLocalPos() + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //AddUnitReport()&lt;br /&gt;
    //send to Coordinator on the broadcastChannel the selected report&lt;br /&gt;
    //format example -&amp;gt; AddUnitReport::unitKey::00000-0000-0000-00000::Report::Successful Completion of Test&lt;br /&gt;
    llSay( broadcastChannel, &amp;quot;AddUnitReport::unitKey::&amp;quot; + (string)llGetKey() + &amp;quot;::Report::&amp;quot; + reportString);&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   errorcheck&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      the body of a http response&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     0 -&amp;gt; error detected&lt;br /&gt;
//////////                  1 -&amp;gt; no error in message&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is used to test the body of a http response for a &lt;br /&gt;
//////////                  error message&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
integer errorcheck(string message)&lt;br /&gt;
{&lt;br /&gt;
 if(debug &amp;gt; 1){llSay(debugChannel, llGetScriptName()+ &amp;quot;:errorcheck &amp;quot;);}&lt;br /&gt;
        &lt;br /&gt;
        //if the word &amp;quot;error&amp;quot; is found in the body&lt;br /&gt;
        if( llSubStringIndex( llToLower(message), &amp;quot;error&amp;quot; ) != -1)&lt;br /&gt;
        {&lt;br /&gt;
            llSay(0, message);&lt;br /&gt;
            //return an error detected reponse&lt;br /&gt;
            return 0;&lt;br /&gt;
        }&lt;br /&gt;
        //if the &amp;quot;404 not found&amp;quot; is present in the body&lt;br /&gt;
        if( llSubStringIndex( llToLower(message), &amp;quot;404 not found&amp;quot; ) != -1)&lt;br /&gt;
        {&lt;br /&gt;
            llSay(0, message);&lt;br /&gt;
            //return an error detected reponse&lt;br /&gt;
            return 0;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        //if it made it past the error detection test, return a passed response &lt;br /&gt;
        return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   HttpVerification&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      the body of a http response&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     sends pass/fail message out via linked message&lt;br /&gt;
//////////                  &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function is used to verify the body of a http response &lt;br /&gt;
//////////                  &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:     format and float precision issue with the location compare &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
HttpVerification(string message)&lt;br /&gt;
{&lt;br /&gt;
    &lt;br /&gt;
    //expect a :: seperated list of the information transmitted in the http headers&lt;br /&gt;
    //format example -&amp;gt; ownername::objectname::objectkey::ownerkey::region::location&lt;br /&gt;
    &lt;br /&gt;
    // dump string parameters into usable list&lt;br /&gt;
    list unitParameters= llParseString2List( message, [&amp;quot;::&amp;quot;], [&amp;quot;&amp;quot;]);&lt;br /&gt;
    &lt;br /&gt;
    //initialize a status variable&lt;br /&gt;
    string passIndication = &amp;quot;PASS&amp;quot;;&lt;br /&gt;
    &lt;br /&gt;
    //ownername&lt;br /&gt;
    if(  llList2String( unitParameters, 0) != llKey2Name( llGetOwner() )  )&lt;br /&gt;
    {&lt;br /&gt;
       passIndication = &amp;quot;FAIL&amp;quot;;    &lt;br /&gt;
       if(debug &amp;gt; 1){llSay(debugChannel, llGetScriptName()+ &amp;quot;:GetOwnerFAIL &amp;quot;);}&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //objectname&lt;br /&gt;
    if(  llList2String( unitParameters, 1) != llGetObjectName()  )&lt;br /&gt;
    {&lt;br /&gt;
       passIndication = &amp;quot;FAIL&amp;quot;;    &lt;br /&gt;
       if(debug &amp;gt; 1){llSay(debugChannel, llGetScriptName()+ &amp;quot;:GetObjectNameFAIL &amp;quot;);}&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //objectkey&lt;br /&gt;
    if(  llList2String( unitParameters, 2) != (string)llGetKey()  )&lt;br /&gt;
    {&lt;br /&gt;
       passIndication = &amp;quot;FAIL&amp;quot;;  &lt;br /&gt;
       if(debug &amp;gt; 1){llSay(debugChannel, llGetScriptName()+ &amp;quot;:GetKeyFAIL &amp;quot;);}  &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //ownerkey&lt;br /&gt;
    if(  llList2String( unitParameters, 3) != (string)llGetOwner()   )&lt;br /&gt;
    {&lt;br /&gt;
       passIndication = &amp;quot;FAIL&amp;quot;;    &lt;br /&gt;
       if(debug &amp;gt; 1){llSay(debugChannel, llGetScriptName()+ &amp;quot;:GetOwnerFAIL &amp;quot;);}&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //region&lt;br /&gt;
    //because the response contains the region grid numbers,&lt;br /&gt;
    //you can not do a direct compare&lt;br /&gt;
    if( llSubStringIndex( llList2String( unitParameters, 4), llGetRegionName() ) == -1)&lt;br /&gt;
    {&lt;br /&gt;
       passIndication = &amp;quot;FAIL&amp;quot;;    &lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    //location&lt;br /&gt;
//    if(  llList2String( unitParameters, 5) != (string)llGetLocalPos()  )&lt;br /&gt;
//    {&lt;br /&gt;
//       passIndication = &amp;quot;FAIL&amp;quot;;    &lt;br /&gt;
//    }    &lt;br /&gt;
    &lt;br /&gt;
     //One of the following messages needs to be sent at the end of this function&lt;br /&gt;
     //each time that it is run&lt;br /&gt;
     //&lt;br /&gt;
     // llMessageLinked(LINK_SET, passFailChannel, &amp;quot;PASS&amp;quot;, NULL_KEY);&lt;br /&gt;
     // llMessageLinked(LINK_SET, passFailChannel, &amp;quot;FAIL&amp;quot;, NULL_KEY);&lt;br /&gt;
     llMessageLinked(LINK_SET, passFailChannel, passIndication, NULL_KEY);&lt;br /&gt;
&lt;br /&gt;
}             &lt;br /&gt;
                 &lt;br /&gt;
//////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Function:   Initialize&lt;br /&gt;
//////////&lt;br /&gt;
//////////      Input:      no input paramaters&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Output:     no return value&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Purpose:    This function initializes any variables or functions necessary&lt;br /&gt;
//////////                  to get us started&lt;br /&gt;
//////////                    &lt;br /&gt;
//////////      Issues:        no known issues &lt;br /&gt;
//////////                    &lt;br /&gt;
//////////                    &lt;br /&gt;
/////////////////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
Initialize()&lt;br /&gt;
{&lt;br /&gt;
&lt;br /&gt;
   llSetText( &amp;quot;Communication_Http&amp;quot;, &amp;lt;255,255,255&amp;gt;, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE STATE//&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                          DEFAULT STATE                                            //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
//                                                                                   //&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
///////////////////////////////////////////////////////////////////////////////////////&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  State Entry of default state                     //&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
   state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
////////////////////////////////////////////////////////&lt;br /&gt;
//  On Rez of default state                           //&lt;br /&gt;
////////////////////////////////////////////////////////    &lt;br /&gt;
    on_rez(integer start_param)&lt;br /&gt;
    {&lt;br /&gt;
        Initialize();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  Link Message of default state                    //&lt;br /&gt;
///////////////////////////////////////////////////////   &lt;br /&gt;
    link_message(integer sender_number, integer number, string message, key id)&lt;br /&gt;
    {&lt;br /&gt;
        if(debug &amp;gt; 1)llSay(debugChannel, llGetScriptName()+ &amp;quot;-&amp;gt;link_message: &amp;quot; + message);&lt;br /&gt;
        &lt;br /&gt;
        //if link message is on the correct channel&lt;br /&gt;
        if(number == toAllChannel)&lt;br /&gt;
        {&lt;br /&gt;
            //treat as command input&lt;br /&gt;
            ParseCommand(message);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
    } //end of link message&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
//  Http Response of default state                   //&lt;br /&gt;
///////////////////////////////////////////////////////&lt;br /&gt;
http_response(key id, integer status, list metadata, string body)&lt;br /&gt;
    {&lt;br /&gt;
       // if(debug &amp;gt; 10){llSay(debugChannel, llGetScriptName()+ &amp;quot;:FUNCTION: DEFAULT HTTP&amp;quot;);}&lt;br /&gt;
       // if(debug &amp;gt; 10){llSay(debugChannel, body);}&lt;br /&gt;
   &lt;br /&gt;
        //if it was a call to setup&lt;br /&gt;
        if(id == HTTP_CONTROL)&lt;br /&gt;
        {    //if we can pass the error check&lt;br /&gt;
             if( errorcheck(body) )&lt;br /&gt;
             { &lt;br /&gt;
                 //expect a :: seperated list of the information transmitted in the http headers&lt;br /&gt;
                 //format example -&amp;gt; ownername::objectname::objectkey::ownerkey::region::location&lt;br /&gt;
                 HttpVerification( body );&lt;br /&gt;
                 &lt;br /&gt;
                 http_body = body; &lt;br /&gt;
             } &lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    } // end http_reponse&lt;br /&gt;
        &lt;br /&gt;
&lt;br /&gt;
} // end default&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LlUnescapeURL&amp;diff=52389</id>
		<title>LlUnescapeURL</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LlUnescapeURL&amp;diff=52389"/>
		<updated>2008-02-02T00:29:54Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LSL_Function&lt;br /&gt;
|func_id=308|func_sleep=0.0|func_energy=10.0&lt;br /&gt;
|func=llUnescapeURL|return_type=string|p1_type=string|p1_name=url&lt;br /&gt;
|func_footnote&lt;br /&gt;
|func_desc&lt;br /&gt;
|return_text=that is an unescaped/unencoded version of url, replacing %20 with spaces etc.&lt;br /&gt;
|spec&lt;br /&gt;
|caveats=&lt;br /&gt;
|constants&lt;br /&gt;
|examples&lt;br /&gt;
|helpers&lt;br /&gt;
|also_functions={{LSL DefineRow||[[llEscapeURL]]| Opposite of llUnescapeURL}}&lt;br /&gt;
|also_events&lt;br /&gt;
|also_tests&lt;br /&gt;
|also_articles=&lt;br /&gt;
{{LSL DefineRow||[[UTF-8]]|}}&lt;br /&gt;
{{LSL DefineRow||{{LSLGC|Base64}}|}}&lt;br /&gt;
|notes&lt;br /&gt;
|permission&lt;br /&gt;
|negative_index&lt;br /&gt;
|sort=UnescapeURL&lt;br /&gt;
|cat1=Encoding&lt;br /&gt;
|cat2=String&lt;br /&gt;
|cat3&lt;br /&gt;
|cat4&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LlEscapeURL&amp;diff=52369</id>
		<title>LlEscapeURL</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LlEscapeURL&amp;diff=52369"/>
		<updated>2008-02-01T21:33:11Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LSL_Function&lt;br /&gt;
|func_id=307|func_sleep=0.0|func_energy=10.0&lt;br /&gt;
|func=llEscapeURL|return_type=string|p1_type=string|p1_name=url&lt;br /&gt;
|func_footnote&lt;br /&gt;
|func_desc&lt;br /&gt;
|return_text=that is the escaped/encoded version of &#039;&#039;&#039;url&#039;&#039;&#039;, replacing spaces with %20 etc. The function will escape any character not in [a-zA-Z0-9] to %xx where xx is the hexadecimal value of the byte.&lt;br /&gt;
|spec&lt;br /&gt;
|caveats=* The function is not appropriate for escaping an URL all at once since the &#039;: &#039; after the protocol and all of the &#039;/&#039; delimiting the various parts. &lt;br /&gt;
*See: {{LSLG|string#Caveats|String:Caveats}}&lt;br /&gt;
|constants&lt;br /&gt;
|examples&lt;br /&gt;
|helpers&lt;br /&gt;
|also_functions={{LSL DefineRow|[[llUnescapeURL]]}}&lt;br /&gt;
|also_events&lt;br /&gt;
|also_tests&lt;br /&gt;
|also_articles={{LSL DefineRow|[[UTF-8]]}}&lt;br /&gt;
{{LSL DefineRow|[[Base64]]}}&lt;br /&gt;
|notes&lt;br /&gt;
|permission&lt;br /&gt;
|negative_index&lt;br /&gt;
|cat1=Encoding&lt;br /&gt;
|cat2=String&lt;br /&gt;
|cat3&lt;br /&gt;
|cat4&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LlSetObjectDesc&amp;diff=52335</id>
		<title>LlSetObjectDesc</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LlSetObjectDesc&amp;diff=52335"/>
		<updated>2008-02-01T19:41:07Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LSL_Function&lt;br /&gt;
|func=llSetObjectDesc&lt;br /&gt;
|func_id=271|func_sleep=0.0|func_energy=10.0&lt;br /&gt;
|p1_type=string|p1_name=desc&lt;br /&gt;
|func_footnote&lt;br /&gt;
|func_desc=Sets the prims description&lt;br /&gt;
|return_text&lt;br /&gt;
|spec&lt;br /&gt;
|caveats=*The object description is limited to 127 bytes, any string longer then that will be truncated.&lt;br /&gt;
*According to [http://jira.secondlife.com/browse/VWR-437 VWR-437] if you set the description to longer then 256 bytes the object may no longer be rezzable. Use caution if using this field to store data.&lt;br /&gt;
|constants&lt;br /&gt;
|examples=&amp;lt;pre&amp;gt;&lt;br /&gt;
//store the owner&#039;s name in the prim description&lt;br /&gt;
touch_start(integer total_number)&lt;br /&gt;
    {&lt;br /&gt;
        string temp;&lt;br /&gt;
&lt;br /&gt;
        temp = llKey2Name(llGetOwner());&lt;br /&gt;
&lt;br /&gt;
        llSetObjectDesc(temp);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|helpers&lt;br /&gt;
|also_functions=&lt;br /&gt;
{{LSL DefineRow||{{LSLG|llGetObjectDesc}}|Returns the object description.}}&lt;br /&gt;
{{LSL DefineRow||{{LSLG|llGetObjectName}}|Gets the object name.}}&lt;br /&gt;
{{LSL DefineRow||{{LSLG|llSetObjectName}}|Sets the object name.}}&lt;br /&gt;
|also_tests&lt;br /&gt;
|also_events&lt;br /&gt;
|also_articles=&lt;br /&gt;
{{LSL DefineRow||[[Prim Attribute Overloading]]}}&lt;br /&gt;
|notes&lt;br /&gt;
|cat1=Prim&lt;br /&gt;
|cat2=Object&lt;br /&gt;
|cat3&lt;br /&gt;
|cat4&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LlSetObjectName&amp;diff=52331</id>
		<title>LlSetObjectName</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LlSetObjectName&amp;diff=52331"/>
		<updated>2008-02-01T19:37:46Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{LSL Function&lt;br /&gt;
|func_id=203&lt;br /&gt;
|func_sleep=0.0&lt;br /&gt;
|func_energy=10.0&lt;br /&gt;
|func=llSetObjectName|sort=SetObjectName&lt;br /&gt;
|p1_type=string&lt;br /&gt;
|p1_name=name&lt;br /&gt;
|func_desc=Sets the prim&#039;s name according to the &#039;&#039;&#039;name&#039;&#039;&#039; parameter.&lt;br /&gt;
|func_footnote=If this function is called from a child prim in a linked set, it will change the name of the child prim and not the root prim.&lt;br /&gt;
|return_text&lt;br /&gt;
|spec&lt;br /&gt;
|caveats=&lt;br /&gt;
#The name is limited to 63 characgters. Longer prim names appeared cut short.&lt;br /&gt;
#The LL client did not reliably show the current name. Misleadingly old names sometimes appeared at Edit &amp;gt; General &amp;gt; Name until you closed and reopened the Edit dialog of the prim.&lt;br /&gt;
|constants&lt;br /&gt;
|examples=&amp;lt;pre&amp;gt;&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        string yyyy1mm1dd = llGetDate();&lt;br /&gt;
        string name = yyyy1mm1dd + &amp;quot; &amp;quot; + llGetObjectName();&lt;br /&gt;
        llOwnerSay(&amp;quot;llSetObjectName(\&amp;quot;&amp;quot; + name + &amp;quot;\&amp;quot;)&amp;quot;);&lt;br /&gt;
        llSetObjectName(name);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
|helpers&lt;br /&gt;
|also_functions=&lt;br /&gt;
{{LSL DefineRow||[[llGetObjectName]]|Get the prims name}}&lt;br /&gt;
{{LSL DefineRow||[[llGetLinkName]]|Get a linked prims name}}&lt;br /&gt;
{{LSL DefineRow||[[llGetObjectDesc]]|Get the prims description}}&lt;br /&gt;
{{LSL DefineRow||[[llSetObjectDesc]]|Set the prims description}}&lt;br /&gt;
|also_tests&lt;br /&gt;
|also_events&lt;br /&gt;
|also_articles&lt;br /&gt;
|notes&lt;br /&gt;
|cat1=Prim&lt;br /&gt;
|cat2&lt;br /&gt;
|cat3&lt;br /&gt;
|cat4&lt;br /&gt;
|}}&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LLSD&amp;diff=46297</id>
		<title>LLSD</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LLSD&amp;diff=46297"/>
		<updated>2007-12-29T00:49:14Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* Binary Serialization */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= The LLSD flexible data system =&lt;br /&gt;
&lt;br /&gt;
The following text is from the comments in the source of the file:&lt;br /&gt;
linden\indra\common\llsd.cpp &lt;br /&gt;
&lt;br /&gt;
LLSD stands [http://blog.secondlife.com/2006/07/19/web-services-serialization-format/#comment-101218][according to Andrew Linden] for &#039;&#039;&#039;Linden Lab Structured Data&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
LLSD provides a flexible data system similar to the data facilities of dynamic languages like Perl and Python.  It is created to support exchange of structured data between loosly coupled systems.  (Here, &amp;quot;loosly coupled&amp;quot; means not compiled together into the same module.)&lt;br /&gt;
	&lt;br /&gt;
Data in such exchanges must be highly tolerant of changes on either side such as:&lt;br /&gt;
- recompilation&lt;br /&gt;
- implementation in a different langauge&lt;br /&gt;
- addition of extra parameters&lt;br /&gt;
- execution of older versions (with fewer parameters)&lt;br /&gt;
&lt;br /&gt;
To this aim, the C++ API of LLSD strives to be very easy to use, and to default to &amp;quot;the right thing&amp;quot; whereever possible.  It is extremely tolerant of errors and unexpected situations.&lt;br /&gt;
	&lt;br /&gt;
The fundamental class is LLSD.  LLSD is a value holding object.  It holds one value that is either undefined, one of the scalar types, or a map or an array.  LLSD objects have value semantics (copying them copies the value, though it can be considered efficient, due to sharing.), and mutable.&lt;br /&gt;
&lt;br /&gt;
Undefined is the singular value given to LLSD objects that are not initialized with any data.  It is also used as the return value for operations that return an LLSD,&lt;br /&gt;
	&lt;br /&gt;
The scalar data types are:&lt;br /&gt;
* Boolean	- true or false&lt;br /&gt;
* Integer	- a 32 bit signed integer&lt;br /&gt;
* Real		- a 64 IEEE 754 floating point value&lt;br /&gt;
* UUID		- a 128 unique value&lt;br /&gt;
* String	- a sequence of zero or more Unicode chracters&lt;br /&gt;
* Date		- an absolute point in time, UTC, with resolution to the second&lt;br /&gt;
* URI		- a String that is a URI&lt;br /&gt;
* Binary	- a sequence of zero or more octets (unsigned bytes)&lt;br /&gt;
	&lt;br /&gt;
A map is a dictionary mapping String keys to LLSD values.  The keys are unique within a map, and have only one value (though that value could be an LLSD array).&lt;br /&gt;
	&lt;br /&gt;
An array is a sequence of zero or more LLSD values.&lt;br /&gt;
&lt;br /&gt;
== Scalar Accessors ==&lt;br /&gt;
&lt;br /&gt;
Function: Fetch a scalar value, converting if needed and possible.&lt;br /&gt;
&lt;br /&gt;
Conversion among the basic types, Boolean, Integer, Real and String, is fully defined.  Each type can be converted to another with a reasonable interpretation.  These conversions can be used as a convenience even when you know the data is in one format, but you want it in another.  Of course, many of these conversions lose information.&lt;br /&gt;
&lt;br /&gt;
Note: These conversions are not the same as Perl&#039;s.  In particular, when converting a String to a Boolean, only the empty string converts to false.  Converting the String &amp;quot;0&amp;quot; to Boolean results in true.&lt;br /&gt;
&lt;br /&gt;
Conversion to and from UUID, Date, and URI is only defined to and from String.  Conversion is defined to be information preserving for valid values of those types.  These conversions can be used when one needs to convert data to or from another system that cannot handle these types natively, but can handle strings.&lt;br /&gt;
&lt;br /&gt;
Conversion to and from Binary isn&#039;t defined.&lt;br /&gt;
&lt;br /&gt;
Conversion of the Undefined value to any scalar type results in a reasonable null or zero value for the type.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Automatic Cast Protection ==&lt;br /&gt;
&lt;br /&gt;
These are not implemented on purpose.  Without them, C++ can perform some conversions that are clearly not what the programmer intended.&lt;br /&gt;
	&lt;br /&gt;
If you get a linker error about these being missing, you have made mistake in your code.  DO NOT IMPLEMENT THESE FUNCTIONS as a fix.&lt;br /&gt;
		&lt;br /&gt;
All of thse problems stem from trying to support char* in LLSD or in std::string.  There are too many automatic casts that will lead to using an arbitrary pointer or scalar type to std::string.&lt;br /&gt;
&lt;br /&gt;
== Attributes and Data ==&lt;br /&gt;
Attributes are only used for encoding parser and formatting instructions. The data in the elements is always data.&lt;br /&gt;
&lt;br /&gt;
== Root Element ==&lt;br /&gt;
The root element is llsd. The root must have only one child element which can be any container or atomic type.&lt;br /&gt;
&lt;br /&gt;
== Atomic Types ==&lt;br /&gt;
Each atomic type represents one value with type information. An atomic does not have a name, but may have attributes to specify format or processing considerations for the parser. &lt;br /&gt;
Consumers of atomics are encouraged to massage the data into the preferred native representation, but further serialization should honor the original type information if possible.&lt;br /&gt;
&lt;br /&gt;
=== undefined ===&lt;br /&gt;
The undefined type is a placeholder to indicate something is there, but it has no value, and cannot be converted to any other atomic type. Though limited in this way, an undefined is still considered a first-class atomic, and is expected to behave like any other atomic structured data type at runtime.&lt;br /&gt;
==== Serialization example ====&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&amp;lt;undef /&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== boolean ===&lt;br /&gt;
A true or false value.&lt;br /&gt;
==== Conversion ====&lt;br /&gt;
{|&lt;br /&gt;
|&#039;&#039;&#039;type&#039;&#039;&#039;||&#039;&#039;&#039;rules&#039;&#039;&#039;||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||unity||&lt;br /&gt;
|-&lt;br /&gt;
|integer||true =&amp;gt; 1, false =&amp;gt; 0||&lt;br /&gt;
|-&lt;br /&gt;
|real||true =&amp;gt; 1.0, false =&amp;gt; 0.0||&lt;br /&gt;
|-&lt;br /&gt;
|uuid||n/a||&lt;br /&gt;
|-&lt;br /&gt;
|string||&#039;true&#039;, &#039;false&#039;||&lt;br /&gt;
|-&lt;br /&gt;
|binary||one byte us-ascii where true =&amp;gt; 1, false =&amp;gt; 0||&lt;br /&gt;
|-&lt;br /&gt;
|date||n/a||&lt;br /&gt;
|-&lt;br /&gt;
|uri||n/a||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Serialization examples ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!-- true --&amp;gt;&lt;br /&gt;
&amp;lt;boolean&amp;gt;1&amp;lt;/boolean&amp;gt;&lt;br /&gt;
&amp;lt;boolean&amp;gt;true&amp;lt;/boolean&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- false --&amp;gt;&lt;br /&gt;
&amp;lt;boolean&amp;gt;0&amp;lt;/boolean&amp;gt;&lt;br /&gt;
&amp;lt;boolean&amp;gt;false&amp;lt;/boolean&amp;gt;&lt;br /&gt;
&amp;lt;boolean /&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== integer ===&lt;br /&gt;
A signed integer value with a representation of 32 bits.&lt;br /&gt;
==== Conversion ====&lt;br /&gt;
{|&lt;br /&gt;
|&#039;&#039;&#039;type&#039;&#039;&#039;||&#039;&#039;&#039;rules&#039;&#039;&#039;||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||0 =&amp;gt; false, all other values =&amp;gt; true||&lt;br /&gt;
|-&lt;br /&gt;
|integer||unity||&lt;br /&gt;
|-&lt;br /&gt;
|real||closest representable number||&lt;br /&gt;
|-&lt;br /&gt;
|uuid||n/a||&lt;br /&gt;
|-&lt;br /&gt;
|string||human readable string||&lt;br /&gt;
|-&lt;br /&gt;
|binary||8 byte network byte order representation||&lt;br /&gt;
|-&lt;br /&gt;
|date||seconds since epoch||&lt;br /&gt;
|-&lt;br /&gt;
|uri||n/a||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Serialization examples ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;integer&amp;gt;289343&amp;lt;/integer&amp;gt;&lt;br /&gt;
&amp;lt;integer&amp;gt;-3&amp;lt;/integer&amp;gt;&lt;br /&gt;
&amp;lt;integer /&amp;gt; &amp;lt;!-- zero --&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== real ===&lt;br /&gt;
A 64 bit double as defined by IEEE.&lt;br /&gt;
==== Conversion ====&lt;br /&gt;
{|&lt;br /&gt;
|&#039;&#039;&#039;type&#039;&#039;&#039;||&#039;&#039;&#039;rules&#039;&#039;&#039;||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||exactly 0 =&amp;gt; false, all other values =&amp;gt; true||&lt;br /&gt;
|-&lt;br /&gt;
|integer||rounded to closest representable number||&lt;br /&gt;
|-&lt;br /&gt;
|real||unity||&lt;br /&gt;
|-&lt;br /&gt;
|uuid||n/a||&lt;br /&gt;
|-&lt;br /&gt;
|string||human readable string||&lt;br /&gt;
|-&lt;br /&gt;
|binary||8 byte network byte order representation||&lt;br /&gt;
|-&lt;br /&gt;
|date||seconds since epoch||&lt;br /&gt;
|-&lt;br /&gt;
|uri||n/a||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Serialization examples ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;real&amp;gt;-0.28334&amp;lt;/real&amp;gt;&lt;br /&gt;
&amp;lt;real&amp;gt;2983287453.3848387&amp;lt;/real&amp;gt;&lt;br /&gt;
&amp;lt;real /&amp;gt; &amp;lt;!-- exactly zero --&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== uuid ===&lt;br /&gt;
A 128 byte unsigned integer.&lt;br /&gt;
==== Conversion ====&lt;br /&gt;
{|&lt;br /&gt;
|&#039;&#039;&#039;type&#039;&#039;&#039;||&#039;&#039;&#039;rules&#039;&#039;&#039;||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||null uuid =&amp;gt; false, all other values =&amp;gt; true||&lt;br /&gt;
|-&lt;br /&gt;
|integer||n/a||&lt;br /&gt;
|-&lt;br /&gt;
|real||n/a||&lt;br /&gt;
|-&lt;br /&gt;
|uuid||unity||&lt;br /&gt;
|-&lt;br /&gt;
|string||standard 8-4-4-4-12 serialization format||&lt;br /&gt;
|-&lt;br /&gt;
|binary||16 byte raw representation||&lt;br /&gt;
|-&lt;br /&gt;
|date||n/a||&lt;br /&gt;
|-&lt;br /&gt;
|uri||n/a||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Serialization examples ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;uuid&amp;gt;d7f4aeca-88f1-42a1-b385-b9db18abb255&amp;lt;/uuid&amp;gt;&lt;br /&gt;
&amp;lt;uuid /&amp;gt; &amp;lt;!-- null uuid &#039;00000000-0000-0000-0000-000000000000&#039; --&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== string ===&lt;br /&gt;
A simple string of any character data which is intended to be human comprehensible.&lt;br /&gt;
&lt;br /&gt;
Strings in the system that hold text a user might see or enter (chat, IM, notecards, AV names, region names,... basically almost everything!) should move to using a consistent set of acceptable characters. This set is:&lt;br /&gt;
&lt;br /&gt;
* Unicode code points U+20 through U+10FFFD&lt;br /&gt;
** except U+D800 through U+DFFF&lt;br /&gt;
** except U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFE, U+2FFF ... U+10FFFE, U+10FFFF&lt;br /&gt;
** except U+FDDD through U+FDEF&lt;br /&gt;
* U+9 (tab, &#039;\t&#039;)&lt;br /&gt;
* U+A (newline or line feed, &#039;\n&#039;)&lt;br /&gt;
* U+D (carriage return, &#039;\r&#039;)&lt;br /&gt;
&lt;br /&gt;
Strings may be sequences of zero or more of these characters. Strings *may* be normalized by mapping line ending sequences to U+A. Do not rely on differences in strings that normalize to the same string.&lt;br /&gt;
&lt;br /&gt;
These choices of valid strings are chosen from Unicode 4.0 which defines the following valid code points:&lt;br /&gt;
* Unicode code points U+0 through U+10FFFD&lt;br /&gt;
** except U+D800 through U+DFFF (the UTF-16 surrogate pair range)&lt;br /&gt;
** except U+FFFE, U+FFFF, U+1FFFE, U+1FFFF, U+2FFE, U+2FFF ... U+10FFFE, U+10FFFF&lt;br /&gt;
** except U+FDDD through U+FDEF (some historical screw up with Arabic)&lt;br /&gt;
&lt;br /&gt;
The choice for special characters &amp;lt; U+20 is because XML defines acceptable text as all valid Unicode code points &amp;gt;= U+20, and U+9, U+A and U+D. The normalization is because XML defines that all line ending sequences are normalized to U+A.&lt;br /&gt;
&lt;br /&gt;
==== Conversion ====&lt;br /&gt;
{|&lt;br /&gt;
|&#039;&#039;&#039;type&#039;&#039;&#039;||&#039;&#039;&#039;rules&#039;&#039;&#039;||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||empty =&amp;gt; false, all other values =&amp;gt; true||&lt;br /&gt;
|-&lt;br /&gt;
|integer||A simple conversion of the initial characters to an integer||&lt;br /&gt;
|-&lt;br /&gt;
|real||A simple conversion of the initial characters to a real number||&lt;br /&gt;
|-&lt;br /&gt;
|uuid||A valid 8-4-4-4-12 is converted to a uuid, all other values =&amp;gt; null uuid||&lt;br /&gt;
|-&lt;br /&gt;
|string||unity||&lt;br /&gt;
|-&lt;br /&gt;
|binary||raw representation of the characters||&lt;br /&gt;
|-&lt;br /&gt;
|date||An interpretation of the string as a date||&lt;br /&gt;
|-&lt;br /&gt;
|uri||An interpretation of the string as a link||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Serialization examples ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;string&amp;gt;The quick brown fox jumped over the lazy dog.&amp;lt;/string&amp;gt;&lt;br /&gt;
&amp;lt;string&amp;gt;540943c1-7142-4fdd-996f-fc90ed5dd3fa&amp;lt;/string&amp;gt;&lt;br /&gt;
&amp;lt;string /&amp;gt; &amp;lt;!-- empty string --&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== binary data ===&lt;br /&gt;
A chunk of binary data.&lt;br /&gt;
The serialization format is allowed to specify an encoding. Parsers must support base64 encoding. Parsers may support base16 and base85.&lt;br /&gt;
==== Conversion ====&lt;br /&gt;
{|&lt;br /&gt;
||&#039;&#039;&#039;type&#039;&#039;&#039;||&#039;&#039;&#039;rules&#039;&#039;&#039;||&lt;br /&gt;
|-&lt;br /&gt;
||boolean||empty =&amp;gt; false, all other values =&amp;gt; true||&lt;br /&gt;
|-&lt;br /&gt;
||integer||len &amp;lt; 4 =&amp;gt; 0, otherwise first four bytes are interpreted as a network byte order integer||&lt;br /&gt;
|-&lt;br /&gt;
||real||len &amp;lt; 8 =&amp;gt; 0, otherwise first eight bytes are interpreted as a network byte order double||&lt;br /&gt;
|-&lt;br /&gt;
||uuid||len &amp;lt; 16 =&amp;gt; null uuid, otherwise first sixteen bytes are interpreted as the raw binary uuid||&lt;br /&gt;
|-&lt;br /&gt;
||string||the raw binary data interpreted as utf-8 character data||&lt;br /&gt;
|-&lt;br /&gt;
||binary||unity||&lt;br /&gt;
|-&lt;br /&gt;
||date||n/a||&lt;br /&gt;
|-&lt;br /&gt;
||uri||the raw binary data interpreted as a utf-8 serialized link||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Serialization examples ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;binary encoding=&amp;quot;base64&amp;quot;&amp;gt;cmFuZG9t&amp;lt;/binary&amp;gt; &amp;lt;!-- base 64 encoded binary data --&amp;gt;&lt;br /&gt;
&amp;lt;binary&amp;gt;dGhlIHF1aWNrIGJyb3duIGZveA==&amp;lt;/binary&amp;gt; &amp;lt;!-- base 64 encoded binary data is default --&amp;gt;&lt;br /&gt;
&amp;lt;binary /&amp;gt; &amp;lt;!-- empty binary blob --&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== date ===&lt;br /&gt;
A specific point in time. Intervals or relative dates are not supported. The serialization and parser only understand ISO-8601 numeric encoding in UTC. The time may be omitted which will be interpreted as midnight at the start of the day. &lt;br /&gt;
==== Conversion ====&lt;br /&gt;
{|&lt;br /&gt;
|&#039;&#039;&#039;type&#039;&#039;&#039;||&#039;&#039;&#039;rules&#039;&#039;&#039;||&lt;br /&gt;
|-&lt;br /&gt;
|boolean||n/a||&lt;br /&gt;
|-&lt;br /&gt;
|integer||seconds since epoch||&lt;br /&gt;
|-&lt;br /&gt;
|real||seconds since epoch||&lt;br /&gt;
|-&lt;br /&gt;
|uuid||n/a||&lt;br /&gt;
|-&lt;br /&gt;
|string||standard serialization format||&lt;br /&gt;
|-&lt;br /&gt;
|binary||n/a||&lt;br /&gt;
|-&lt;br /&gt;
|date||unity||&lt;br /&gt;
|-&lt;br /&gt;
|uri||n/a||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Serialization examples ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;date&amp;gt;2006-02-01T14:29:53Z&amp;lt;/date&amp;gt;&lt;br /&gt;
&amp;lt;date /&amp;gt; &amp;lt;!-- epoch --&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== uri ===&lt;br /&gt;
A link to an external resource. The data is expected to conform to [http://www.ietf.org/rfc/rfc2396.txt rfc 2396] for interpretation, meaning, serialization, and deserialization.&lt;br /&gt;
==== Conversion ====&lt;br /&gt;
{|&lt;br /&gt;
||&#039;&#039;&#039;type&#039;&#039;&#039;||&#039;&#039;&#039;rules&#039;&#039;&#039;||&lt;br /&gt;
|-&lt;br /&gt;
||boolean||n/a||&lt;br /&gt;
|-&lt;br /&gt;
||integer||n/a||&lt;br /&gt;
|-&lt;br /&gt;
||real||n/a||&lt;br /&gt;
|-&lt;br /&gt;
||uuid||n/a||&lt;br /&gt;
|-&lt;br /&gt;
||string||standard serialization format||&lt;br /&gt;
|-&lt;br /&gt;
||binary||n/a||&lt;br /&gt;
|-&lt;br /&gt;
||date||n/a||&lt;br /&gt;
|-&lt;br /&gt;
||uri||unity||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Serialization examples ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;uri&amp;gt;http://sim956.agni.lindenlab.com:12035/runtime/agents&amp;lt;/uri&amp;gt;&lt;br /&gt;
&amp;lt;uri /&amp;gt; &amp;lt;!-- an empty link --&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Containers ==&lt;br /&gt;
Containers is a special data type which can contain any other data type including other containers.&lt;br /&gt;
&lt;br /&gt;
=== map ===&lt;br /&gt;
A map of key and value pairs where key ordering is unspecified and keys are unique. The key is always interpreted as a character string and any character string is acceptable. If there are any elements in the map, it is serialized as a key followed by an atomic or container value. For every key, there must be one value.&lt;br /&gt;
Well formed and valid serialized maps may contain more non-unique keys. When a deserialized, the implementation should choose one of the the value objects, but that choice is not specified.&lt;br /&gt;
==== Serialization example ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;map&amp;gt;&lt;br /&gt;
 &amp;lt;key&amp;gt;foo&amp;lt;/key&amp;gt;&lt;br /&gt;
 &amp;lt;string&amp;gt;bar&amp;lt;/string&amp;gt;&lt;br /&gt;
 &amp;lt;key&amp;gt;agent info&amp;lt;/key&amp;gt;&lt;br /&gt;
 &amp;lt;map&amp;gt;&lt;br /&gt;
  &amp;lt;key&amp;gt;agent_id&amp;lt;/key&amp;gt;&lt;br /&gt;
  &amp;lt;uuid&amp;gt;93c73b16-cd86-434d-8b4a-76e12eee950a&amp;lt;/uuid&amp;gt;&lt;br /&gt;
  &amp;lt;key&amp;gt;name&amp;lt;/key&amp;gt;&lt;br /&gt;
  &amp;lt;string&amp;gt;testtest tester&amp;lt;/string&amp;gt;&lt;br /&gt;
 &amp;lt;/map&amp;gt;&lt;br /&gt;
&amp;lt;/map&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== array ===&lt;br /&gt;
An ordered collection of data members. Any member can be any atomic or container type.&lt;br /&gt;
==== Serialization example ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;array&amp;gt;&lt;br /&gt;
 &amp;lt;real&amp;gt;7343.0194&amp;lt;/real&amp;gt;&lt;br /&gt;
 &amp;lt;array&amp;gt;&lt;br /&gt;
  &amp;lt;map&amp;gt;&lt;br /&gt;
   &amp;lt;key&amp;gt;offset&amp;lt;/key&amp;gt;&lt;br /&gt;
   &amp;lt;integer&amp;gt;9847&amp;lt;/integer&amp;gt;&lt;br /&gt;
  &amp;lt;/map&amp;gt;&lt;br /&gt;
  &amp;lt;string&amp;gt;da boom&amp;lt;/string&amp;gt;&lt;br /&gt;
 &amp;lt;/array&amp;gt;&lt;br /&gt;
&amp;lt;/array&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= xml-llsd DTD =&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;!DOCTYPE llsd [&lt;br /&gt;
&amp;lt;!ELEMENT llsd (DATA)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT DATA (ATOMIC|map|array)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT ATOMIC (undef|boolean|integer|real|uuid|string|date|uri|binary)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT KEYDATA (key,DATA)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT key (#PCDATA)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT map (KEYDATA*)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT array (DATA*)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT undef (EMPTY)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT boolean (#PCDATA)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT integer (#PCDATA)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT real (#PCDATA)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT uuid (#PCDATA)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT string (#PCDATA)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT date (#PCDATA)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT uri (#PCDATA)&amp;gt;&lt;br /&gt;
&amp;lt;!ELEMENT binary (#PCDATA)&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!ATTLIST string xml:space (default|preserve) &#039;preserve&#039;&amp;gt;&lt;br /&gt;
&amp;lt;!ATTLIST binary encoding CDATA &amp;quot;base64&amp;quot;&amp;gt;&lt;br /&gt;
]&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Example XML Output =&lt;br /&gt;
This is a sample from a recently running sim (indention for readability):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ curl http://localhost:12035/runtime/statistics&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;&lt;br /&gt;
&amp;lt;llsd&amp;gt;&lt;br /&gt;
&amp;lt;map&amp;gt;&lt;br /&gt;
  &amp;lt;key&amp;gt;region_id&amp;lt;/key&amp;gt;&lt;br /&gt;
    &amp;lt;uuid&amp;gt;67153d5b-3659-afb4-8510-adda2c034649&amp;lt;/uuid&amp;gt;&lt;br /&gt;
  &amp;lt;key&amp;gt;scale&amp;lt;/key&amp;gt;&lt;br /&gt;
    &amp;lt;string&amp;gt;one minute&amp;lt;/string&amp;gt;&lt;br /&gt;
  &amp;lt;key&amp;gt;simulator statistics&amp;lt;/key&amp;gt;&lt;br /&gt;
  &amp;lt;map&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;time dilation&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0.9878624&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;sim fps&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;44.38898&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;pysics fps&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;44.38906&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;agent updates per second&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;nan&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;lsl instructions per second&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;total task count&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;4&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;active task count&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;active script count&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;4&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;main agent count&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;child agent count&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;inbound packets per second&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;1.228283&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;outbound packets per second&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;1.277508&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;pending downloads&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;pending uploads&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0.0001096525&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;frame ms&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0.7757886&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;net ms&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0.3152919&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;sim other ms&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0.1826937&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;sim physics ms&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0.04323055&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;agent ms&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0.01599029&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;image ms&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0.01865955&amp;lt;/real&amp;gt;&lt;br /&gt;
    &amp;lt;key&amp;gt;script ms&amp;lt;/key&amp;gt;&amp;lt;real&amp;gt;0.1338836&amp;lt;/real&amp;gt;&lt;br /&gt;
  &amp;lt;/map&amp;gt;&lt;br /&gt;
&amp;lt;/map&amp;gt;&lt;br /&gt;
&amp;lt;/llsd&amp;gt;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Binary Serialization =&lt;br /&gt;
We also have support for binary serialization and deserialization in c++ and python. The binary format is useful when dealing where optimal parse time is necessary. Binary LLSD is the binary llsd prefix followed by a single LLSD element of any type.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?llsd/binary?&amp;gt;\n&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Binary element serialization&lt;br /&gt;
! type !! serialization !! notes&lt;br /&gt;
|-&lt;br /&gt;
| undef || &#039;!&#039;&lt;br /&gt;
|-&lt;br /&gt;
| true || &#039;1&#039;&lt;br /&gt;
|-&lt;br /&gt;
| false || &#039;0&#039;&lt;br /&gt;
|-&lt;br /&gt;
| integer || &#039;i&#039; + htonl(value)&lt;br /&gt;
|-&lt;br /&gt;
| real || &#039;r&#039; + htond(value)&lt;br /&gt;
|-&lt;br /&gt;
| uuid || &#039;u&#039; + uuid || uuid is 16 bytes&lt;br /&gt;
|-&lt;br /&gt;
| binary || &#039;b&#039; + htonl(binary.size()) + binary&lt;br /&gt;
|-&lt;br /&gt;
| string || &#039;s&#039; + htonl(string.size()) + string || notation serialization is considered valid&lt;br /&gt;
|-&lt;br /&gt;
| uri || &#039;l&#039; + htonl(uri.size()) + uri&lt;br /&gt;
|-&lt;br /&gt;
| date || &#039;d&#039; + htond(seconds_since_epoch)&lt;br /&gt;
|-&lt;br /&gt;
| array || &#039;[&#039; + htonl(array.length()) + (child0, child1, ...) + &#039;]&#039; || order is always preserved&lt;br /&gt;
|-&lt;br /&gt;
| map || &#039;{&#039; + htonl(map.length()) + ((key0,value0), (key1, value1), ...)+ &#039;}&#039; || order is not always preserved.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;size()&amp;lt;/b&amp;gt; is a byte count.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;length()&amp;lt;/b&amp;gt; is a child count.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;htonl()&amp;lt;/b&amp;gt; is a function to generate a 4 byte network byte order integer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;htond()&amp;lt;/b&amp;gt; is a function to generate an 8 byte network byte order double. htond is not a standard system call, but you can find a c implementation in &amp;lt;code&amp;gt;indra/llcommon/llsdserialize.cpp&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= Notation Serialization =&lt;br /&gt;
We also have support for a serialization format meant for human readability. Parsing and formatting are currently only available in c++. Notation LLSD is the notation llsd prefix followed by a single LLSD element of any type.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?llsd/notation?&amp;gt;\n&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Binary element serialization&lt;br /&gt;
! type !! serialization !! notes&lt;br /&gt;
|-&lt;br /&gt;
| undef || &#039;!&#039;&lt;br /&gt;
|-&lt;br /&gt;
| true || &amp;lt;nowiki&amp;gt;&#039;1&#039; |  &#039;t&#039; | &#039;T&#039; | &#039;true&#039; | &#039;TRUE&#039;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| false || &amp;lt;nowiki&amp;gt;&#039;0&#039; |  &#039;f&#039; | &#039;F&#039; | &#039;false&#039; | &#039;FALSE&#039;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| integer || &#039;i&#039; str(value)&lt;br /&gt;
|-&lt;br /&gt;
| real || &#039;r&#039; str(value)&lt;br /&gt;
|-&lt;br /&gt;
| uuid || &#039;u&#039; str(uuid)&lt;br /&gt;
|-&lt;br /&gt;
| binary || &amp;lt;nowiki&amp;gt;&#039;b(&#039; str(size) &#039;)&amp;quot;&#039;  raw_data &#039;&amp;quot;&#039; | &#039;b&#039; base &#039;&amp;quot;&#039; encoded_data &#039;&amp;quot;&#039;&amp;lt;/nowiki&amp;gt;  || Base 16 and 64 encodings are supported.&lt;br /&gt;
|-&lt;br /&gt;
| string || &amp;lt;nowiki&amp;gt;&amp;quot; escaped_string &amp;quot; | &#039; escaped_string &#039; | &#039;s(&#039; str(size) &#039;)&amp;quot;&#039; raw_string &#039;&amp;quot;&#039;&amp;lt;/nowiki&amp;gt; || When using single quotes, double quotes do not need escaping and vice versa.&lt;br /&gt;
|-&lt;br /&gt;
| uri || &#039;l&amp;quot;&#039; escaped_uri &#039;&amp;quot;&#039; || See [http://www.faqs.org/rfcs/rfc1738.html rfc 1738] for encoding rules.&lt;br /&gt;
|-&lt;br /&gt;
| date || &#039;d&amp;quot;&#039; YYYY-MM-DD &#039;T&#039; HH:MM:SS [.FF] &#039;Z&amp;quot;&#039; || Fractional seconds are optional&lt;br /&gt;
|-&lt;br /&gt;
| array || &#039;[&#039; object0 &#039;,&#039; object1 &#039;,&#039; ... &#039;]&#039; || order is always preserved&lt;br /&gt;
|-&lt;br /&gt;
| map || &#039;{&#039; string0:object0 &#039;,&#039; string1:object1 &#039;,&#039; ... &#039;}&#039; || order is not always preserved. The string is any supported string serialization format&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== String Escaping ==&lt;br /&gt;
Strings which contain non-printable characters delimited with quotes or double quotes require escaping. If a single quote delimited string contains single quotes, those must be escaped. If a double quote delimited string contains double quotes, the double quotes must be escaped.&lt;br /&gt;
&lt;br /&gt;
To escape the delimiter character, prefix a backslash. Backslashes must always be escaped with another backslash.&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;And then he said, \&amp;quot;I have nothing more to say on the subject.\&amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
 &#039;Look in &amp;quot;C:\\linden\\&amp;quot;&#039;&lt;br /&gt;
&lt;br /&gt;
The most generic escaping is to specify a hex value of the byte after a literal backslash and character &#039;x&#039;. This can be used for any character and is required for all non-printable characters which do not have an abbreviation. For example:&lt;br /&gt;
&lt;br /&gt;
  \x0C&lt;br /&gt;
&lt;br /&gt;
Serialized strings should only contain UTF-8 characters, so non-printable characters other than tab, newline, and carriage return should be avoided. However, common non-printable characters have short-hand abbreviations.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Notation abbreviations&lt;br /&gt;
! character !! value !! serialization&lt;br /&gt;
|-&lt;br /&gt;
| alert/bell ||  0x7 || \a&lt;br /&gt;
|-&lt;br /&gt;
| backspace || 0x8 || \b&lt;br /&gt;
|-&lt;br /&gt;
| form feed || 0xc || \f&lt;br /&gt;
|-&lt;br /&gt;
| newline || 0xa || \n&lt;br /&gt;
|-&lt;br /&gt;
| carriage return || 0xd || \r&lt;br /&gt;
|-&lt;br /&gt;
| horizontal tab || 0x9 || \t&lt;br /&gt;
|-&lt;br /&gt;
| vertical tab || 0xb || \v&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Example Notation Output ==&lt;br /&gt;
This is an excerpt from an agent request to enter a region serialized as notation:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[&lt;br /&gt;
  {&#039;destination&#039;:&#039;http://secondlife.com&#039;}, &lt;br /&gt;
  {&#039;version&#039;:i1}, &lt;br /&gt;
  {&lt;br /&gt;
    &#039;agent_id&#039;:u3c115e51-04f4-523c-9fa6-98aff1034730, &lt;br /&gt;
    &#039;session_id&#039;:u2c585cec-038c-40b0-b42e-a25ebab4d132, &lt;br /&gt;
    &#039;circuit_code&#039;:i1075, &lt;br /&gt;
    &#039;first_name&#039;:&#039;Phoenix&#039;, &lt;br /&gt;
    &#039;last_name&#039;:&#039;Linden&#039;,&lt;br /&gt;
    &#039;position&#039;:[r70.9247,r254.378,r38.7304], &lt;br /&gt;
    &#039;look_at&#039;:[r-0.043753,r-0.999042,r0], &lt;br /&gt;
    &#039;granters&#039;:[ua2e76fcd-9360-4f6d-a924-000000000003],&lt;br /&gt;
    &#039;attachment_data&#039;:&lt;br /&gt;
    [&lt;br /&gt;
      {&lt;br /&gt;
        &#039;attachment_point&#039;:i2,&lt;br /&gt;
        &#039;item_id&#039;:ud6852c11-a74e-309a-0462-50533f1ef9b3,&lt;br /&gt;
        &#039;asset_id&#039;:uc69b29b1-8944-58ae-a7c5-2ca7b23e22fb&lt;br /&gt;
      },&lt;br /&gt;
      {&lt;br /&gt;
        &#039;attachment_point&#039;:i10, &lt;br /&gt;
        &#039;item_id&#039;:uff852c22-a74e-309a-0462-50533f1ef900,&lt;br /&gt;
        &#039;asset_id&#039;:u5868dd20-c25a-47bd-8b4c-dedc99ef9479&lt;br /&gt;
      }&lt;br /&gt;
    ]&lt;br /&gt;
  }&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[&lt;br /&gt;
  {&lt;br /&gt;
    &#039;creation-date&#039;:d&amp;quot;2007-03-15T18:30:18Z&amp;quot;, &lt;br /&gt;
    &#039;creator-id&#039;:u3c115e51-04f4-523c-9fa6-98aff1034730&lt;br /&gt;
  },&lt;br /&gt;
  s(10)&amp;quot;0123456789&amp;quot;,&lt;br /&gt;
  &amp;quot;Where&#039;s the beef?&amp;quot;,&lt;br /&gt;
  &#039;Over here.&#039;,  &lt;br /&gt;
  b(160)&amp;quot;default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSay(0, &amp;quot;Hello, Avatar!&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    touch_start(integer total_number)&lt;br /&gt;
    {&lt;br /&gt;
        llSay(0, &amp;quot;Touched.&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
}&amp;quot;,&lt;br /&gt;
  b64&amp;quot;AABAAAAAAAAAAAIAAAA//wAAP/8AAADgAAAA5wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&lt;br /&gt;
AABkAAAAZAAAAAAAAAAAAAAAZAAAAAAAAAABAAAAAAAAAAAAAAAAAAAABQAAAAEAAAAQAAAAAAAA&lt;br /&gt;
AAUAAAAFAAAAABAAAAAAAAAAPgAAAAQAAAAFAGNbXgAAAABgSGVsbG8sIEF2YXRhciEAZgAAAABc&lt;br /&gt;
XgAAAAhwEQjRABeVAAAABQBjW14AAAAAYFRvdWNoZWQuAGYAAAAAXF4AAAAIcBEI0QAXAZUAAEAA&lt;br /&gt;
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&amp;quot; &lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Guidelines =&lt;br /&gt;
== XML Encoding ==&lt;br /&gt;
When possible, prefer using us-ascii or or UTF-8 xml encoding.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Questions &amp;amp; Things To Do ===&lt;br /&gt;
&lt;br /&gt;
Would Binary be more convenient as usigned char* buffer semantics?&lt;br /&gt;
&lt;br /&gt;
Should Binary be convertable to/from String, and if so how?&lt;br /&gt;
* as UTF8 encoded strings (making not like UUID&amp;lt;-&amp;gt;String)&lt;br /&gt;
* as Base64 or Base96 encoded (making like UUID&amp;lt;-&amp;gt;String)&lt;br /&gt;
&lt;br /&gt;
Conversions to std::string and LLUUID do not result in easy assignment to std::string, LLString or LLUUID due to non-unique conversion paths.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Certified_HTTP&amp;diff=42890</id>
		<title>Certified HTTP</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Certified_HTTP&amp;diff=42890"/>
		<updated>2007-12-02T18:19:02Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* X-Message-URL */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Goals =&lt;br /&gt;
The basic goal of Certified HTTP (colloquially known as chttp) is to perform exactly-once messaging between two hosts.&lt;br /&gt;
&lt;br /&gt;
From a standard http client perspective, if the client reads a whole response, then it knows for certain the server handled the request. However, for all other failure modes, the client can&#039;t be sure if the server did, or did-not perform the request function. On the server side, the server can never know if the client ever got the answer or not. For some operations, we need the ability for the client to perform a data-altering operation and be insistent that it occur. In particular, if it isn&#039;t certain that it happened, then it must be able to try again safely.&lt;br /&gt;
&lt;br /&gt;
The bigger picture goal is to make a simple way to conduct reliable delivery and receipt such that general adoption by the wider community is possible. This means that we have to respect HTTP where we can to take advantage of existing tools and methodology and to never contradict common conventions in a REST world.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Join the [https://lists.secondlife.com/cgi-bin/mailman/listinfo/chttpdev mailing list].&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Workflow =&lt;br /&gt;
&lt;br /&gt;
The workflow is a specification/pseudocode for what actions both ends of chttp communication need to take to fulfill the requirements.&lt;br /&gt;
&lt;br /&gt;
== Interaction Sequence ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a diagram that describes an everything-works certified http communication.&lt;br /&gt;
&lt;br /&gt;
[[Image:Interaction_sequence.png]]&lt;br /&gt;
&lt;br /&gt;
Of note are the failure points.  These are the effective crash locations of the participants (the failure points on the arrows represent communication failures).  Actions that intervene between two failure points should be deterministic and/or atomic enough that a crash occurring midway through them is functionally identical to a crash occurring at the immediately prior failure point.&lt;br /&gt;
&lt;br /&gt;
The [[Certified HTTP Failure Diagrams]] page (warning: &#039;&#039;&#039;very&#039;&#039;&#039; image-heavy) has a relatively-exhaustive exploration of the way a Certified HTTP implementation should behave in the face of failures.&lt;br /&gt;
&lt;br /&gt;
== Sending a Message ==&lt;br /&gt;
&lt;br /&gt;
The sending-side API looks very much like a normal HTTP method call:&lt;br /&gt;
  response = certified_http.put(url, body)&lt;br /&gt;
&lt;br /&gt;
What happens under the covers is:&lt;br /&gt;
# Generate a globally unique message ID for the message&lt;br /&gt;
# Store the outgoing request (headers and all), including the message id, in a durable store &amp;quot;outbox&amp;quot;, and waits for a response.&lt;br /&gt;
# A potentially asynchronous process performs the following steps:&lt;br /&gt;
## Retrieves the request from the outbox.&lt;br /&gt;
## Performs the HTTP request specified by the outbox request and waits for a response.&lt;br /&gt;
## If a response is not forthcoming, for whatever reason, the process retries after a certain period.&lt;br /&gt;
## If the server sends an error code that indicates that the reliable message will never complete (e.g. 501), or a long timeout expires indicating that an absurd amount of time has elapsed, the method throws an exception.&lt;br /&gt;
# Opens a transaction on the durable store&lt;br /&gt;
# Stores the incoming response in a durable inbox.&lt;br /&gt;
# &#039;Tombstones&#039; the message in the outbox, which essentially marks the message as having been received, so that if the application resumes again, it doesn&#039;t resend.&lt;br /&gt;
# Closes the transaction on the durable store&lt;br /&gt;
# If the response contains a header indicating a confirmation url on the recipient, performs an HTTP DELETE on the resource to ack the incoming message.&lt;br /&gt;
&lt;br /&gt;
There are no explicit semantics for the response body, like HTTP itself.  The content will vary depending on the application.&lt;br /&gt;
&lt;br /&gt;
== Receiving a Message ==&lt;br /&gt;
&lt;br /&gt;
The receiver sets up a node in the url hierarchy, just like a regular http node.  When an incoming request comes in, the receiver:&lt;br /&gt;
&lt;br /&gt;
# Stores the incoming request in a durable store &amp;quot;inbox&amp;quot;, if it doesn&#039;t already contain a message with the same ID.&lt;br /&gt;
# A potentially asynchronous process performs the following steps:&lt;br /&gt;
## Looks for responses in the outbox matching the incoming message id, and if it finds one, sends it as the response without invoking anything else.&lt;br /&gt;
## Opens a transaction on the database, locking the inbox request&lt;br /&gt;
## Calls the handler method on the receiving node:&lt;br /&gt;
### &amp;lt;code&amp;gt;def handle_put(body, txn):&amp;lt;br/&amp;gt;return &amp;quot;My Response&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
### The handler method can use the open transaction to perform actions in the database that are atomic with the receipt of the message.  Any non-idempotent operation must be done atomically in this way.&lt;br /&gt;
## Stores the return value of the handle method as an outgoing response in the outbox, without closing the transaction. &lt;br /&gt;
## Removes the incoming request from the inbox&lt;br /&gt;
## Closes the transaction&lt;br /&gt;
# Discovers a new item in the outbox, responds to the incoming http request with the response from the outbox, including a url that, if DELETEd, will remove the item from the outbox.&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
&lt;br /&gt;
We have the concept of a &amp;quot;long&amp;quot; time (LT).  The purpose of this time is to ensure that any clients will stop trying a particular request long before the server discards state associated with the request.  This is not a very theoretically &amp;quot;pure&amp;quot; concept, since it relies on all parties conforming to certain (reasonable) assumptions, but we believe that we get significant benefits (lack of explicit negotiation), at little risk of actually entering an incorrect state.   chttp is expected to generate a small amount of bookkeeping data for each message, and there needs to be a way to expire this data in a way that doesn&#039;t involve additional negotiation between servers and clients.  The server should keep data for LT, and clients should not retry messages that are older than LT/2 or similar, so that there is at least LT/2 for a Reliable Host to recover from errors, and LT/2 for clock skew.  LT therefore should be orders of magnitude longer than the longest downtime we expect to see in the system and the largest clock skew we expect to see.  Off the cuff, 30 days seems like a reasonable value for LT.&lt;br /&gt;
&lt;br /&gt;
* chttp is based on http, and can use any facility provided by http 1.1 where not otherwise contradicted.&lt;br /&gt;
** this includes the use of https, pipelining, chunked encoding, proxies, redirects, caches, and headers such as Accept, Accept-Encoding, Expect, and Content-Type.&lt;br /&gt;
** any normal http verb appropriate to context should be accepted, eg POST, PUT, GET, DELETE&lt;br /&gt;
** unless otherwise specified, the http feature set in use is orthogonal and effectively transparent to chttp&lt;br /&gt;
* in any complete chttp exchange the client and server can eventually agree on success or failure of delivery, though it is more important that no ill effects arise when they disagree&lt;br /&gt;
* any message will be effectively received once and only once or not at all&lt;br /&gt;
* the content of the http body must be opaque to chttp&lt;br /&gt;
* the URI of the original request must be opaque to chttp&lt;br /&gt;
* chttp enabled clients and servers can integrate with unreliable tools&lt;br /&gt;
** the chttp server can differentiate reliable requests and respond without reliability guarantees (i.e. act as a normal http server)&lt;br /&gt;
** chttp clients can differentiate reliable responses and handle unreliable servers (i.e. act as a normal http client)&lt;br /&gt;
* the client will persist the local time of sending&lt;br /&gt;
* if there is one the client must either have the persisted outgoing body or the exact same body can be regenerated on the fly&lt;br /&gt;
* the server will persist the local time of message receipt&lt;br /&gt;
* the server must persist the response body or have a mechanism to idempotently generate the same response to the same request&lt;br /&gt;
* all urls with a chttp server behind them are effectively idempotent for all uniquely identified messages&lt;br /&gt;
** the client can retry steadily over a period of LT/2 days&lt;br /&gt;
** the client and server are assumed to almost always be running&lt;br /&gt;
** over that window of opportunity, the same message will always get the same response&lt;br /&gt;
* all persisted data on a single host is ACID&lt;br /&gt;
&lt;br /&gt;
== requirements on top of http ==&lt;br /&gt;
* if the body of the request is non-zero length, the client MUST include a Content-Length header, unless prohibited by section 4.4 of [http://www.w3.org/Protocols/rfc2616/rfc2616.html RFC 2616]&lt;br /&gt;
** the server will look for \r\n\r\n and content length body to consider the request complete&lt;br /&gt;
** an incomplete request will result in 4XX status code&lt;br /&gt;
* if the body of the response is non-zero length, the server must include a Content-Length header&lt;br /&gt;
** the client will look for \r\n\r\n and content length body to consider the response complete&lt;br /&gt;
** the client will retry on an incomplete response&lt;br /&gt;
* Messages can not be terminated by closing the connection -- only positive expressions of message termination (such as Content-Length) can guarantee that a full message is received.&lt;br /&gt;
&lt;br /&gt;
== assumptions ==&lt;br /&gt;
&lt;br /&gt;
* The client and server will not have any significant time discontinuity, i.e., the clock difference between them should be less than LT/100.&lt;br /&gt;
* The client and server will not have clock drift more than LT/100 per day.&lt;br /&gt;
* Both parties exchanging messages are Reliable Hosts (defined below).&lt;br /&gt;
* Generating a globally unique message ID is inexpensive.&lt;br /&gt;
* It is possible to store a large amount of &#039;small&#039; data (such as [[UUID]]s, urls, and date/timestamps) for LT.  &amp;quot;Large&amp;quot; in this case means &amp;quot;as many items as the throughput of a host implies that you could create during LT&amp;quot;.  In other words, storing this small data will never be a resource problem.&lt;br /&gt;
* Any transaction or data handled by this system will become useless well before LT has elapsed.  &lt;br /&gt;
&lt;br /&gt;
; Reliable Host : A reliable host has the following properties:&lt;br /&gt;
* The host has a durable data store of finite size, which can store data in such a way that it is guaranteed to be recoverable even in the face of a certain number of hardware failures.&lt;br /&gt;
* The host will not be down forever.  Either a clone will be brought up on different hardware, or the machine itself will reappear within a day or so. &lt;br /&gt;
* The host can perform {{Wikipedia|ACID|w=n}} operations on the data it contains.&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
Requiring an opaque body and URI pretty much requires either negotiating an URL beforehand or adding new headers. Since the former was discarded earlier (reliable delivery after setup), we will focus on adding request and response headers.&lt;br /&gt;
&lt;br /&gt;
This is a suggested implementation:&lt;br /&gt;
# chttp enabled servers will behave idempotently with a unique message id on the request&lt;br /&gt;
# the server can request acknowledgment from the client if the request consumes server resources&lt;br /&gt;
&lt;br /&gt;
== Request ==&lt;br /&gt;
A client will start a reliable message by making an HTTP request to a url on a reliable http server. The url may be known in advance or returned as part of an earlier application protocol exchange.  The request must contain two headers on top of the headers required by HTTP/1.1: X-Message-Id and Date.&lt;br /&gt;
&lt;br /&gt;
=== X-Message-ID ===&lt;br /&gt;
A globally unique id.  It must match the regular expression &amp;lt;code&amp;gt;^[A-Za-z0-9-_:]{30,100}$&amp;lt;/code&amp;gt;.  This header is required for all Certified HTTP interactions.&lt;br /&gt;
&lt;br /&gt;
The best practice for generating this id is to combine a client host identifier with a cryptographically secure uuid and a sequence number.&lt;br /&gt;
&lt;br /&gt;
Sending a message with the same message id but a a different body has an undefined result.&lt;br /&gt;
&lt;br /&gt;
Sending a message with the same message id but with a different header which implies a different response body, eg, the first request specifies &amp;quot;Accept: text/plain&amp;quot; and the second request specifies &amp;quot;Accept: text/html&amp;quot;, the response can be one of:&lt;br /&gt;
&lt;br /&gt;
* The original response.&lt;br /&gt;
* A 4xx indicating that the server has detected the incompatability&lt;br /&gt;
&lt;br /&gt;
It is preferable to return the original response rather than the 4xx, but some implementations may not be able to achieve that.&lt;br /&gt;
&lt;br /&gt;
=== Date ===&lt;br /&gt;
&lt;br /&gt;
The Date header, as specified in RFC2616.  Certified HTTP requires a date header on all requests, which differs somewhat from RFC2616.&lt;br /&gt;
&lt;br /&gt;
== Response ==&lt;br /&gt;
Generally, when the client gets the 2XX back from the server, the message has been delivered. If the server has a response body, then the client will need to acknowledge receipt of the entire body. If the entire body is not read, the client can safely resubmit the exact same request. The server will include a message url in the headers if the client specified a message id on request and the body requires persistence by the server.&lt;br /&gt;
&lt;br /&gt;
=== X-Message-URL ===&lt;br /&gt;
This will be a unique url on the server for the client message id which the client will DELETE upon receipt of the entire response to the request. This will only exist if there is a non-null response body or the server is consuming significant resources to maintain that url. When the client performs the delete, the server can flush all persisted resources other than the fact that the message was sent at some point.&lt;br /&gt;
&lt;br /&gt;
== Status Codes ==&lt;br /&gt;
&lt;br /&gt;
The semantics of Certified HTTP are to retry until the message goes through.  HTTP status codes provide one way of determining whether the message made it or not;  we&#039;ve grouped these status codes into &#039;success&#039; or &#039;retry&#039;.   In many cases they can signify that the client is attempting to send an invalid message, an error in the application logic; these are labeled as &#039;fail&#039;.  There is a third class, where the status code may be ambiguous; e.g. 404, which is often emitted by temporarily-misconfigured webservers, but may also indicate that an incorrect url was chosen.&lt;br /&gt;
&lt;br /&gt;
=== Success ===&lt;br /&gt;
&lt;br /&gt;
These status codes, when received, give the client permission to do whatever cleanup it needs to do, and to return to caller, safe in the assumption that the message was delivered.&lt;br /&gt;
&lt;br /&gt;
* 200 OK&lt;br /&gt;
* 201 Created&lt;br /&gt;
* 203 Non-Authoritative Information&lt;br /&gt;
* 204 No Content&lt;br /&gt;
* 205 Reset Content&lt;br /&gt;
* 206 Partial Content&lt;br /&gt;
* 304 Not Modified&lt;br /&gt;
&lt;br /&gt;
=== Retry ===&lt;br /&gt;
&lt;br /&gt;
These status codes indicate a temporary failure or misconfiguration on the server side, and therefore the client should retry until it gets something different.  All the redirected/proxied messages carry the same message-id.&lt;br /&gt;
&lt;br /&gt;
* 202 Accepted (potentially delaying longer than normal)&lt;br /&gt;
* 300 Multiple Choices (follow redirect)&lt;br /&gt;
* 302 Found (follow redirect)&lt;br /&gt;
* 305 Use Proxy (use proxy)&lt;br /&gt;
* 307 Temporary Redirect (follow redirect only if GET)&lt;br /&gt;
* 408 Request Timeout (retry with a new message-id and date)&lt;br /&gt;
* 413 Request Entity Too Large (if Retry-After header present)&lt;br /&gt;
* 502 Bad Gateway&lt;br /&gt;
* 503 Service Unavailable&lt;br /&gt;
* 504 Gateway Timeout&lt;br /&gt;
&lt;br /&gt;
=== Fail ===&lt;br /&gt;
&lt;br /&gt;
If your application logic screws up and picks an improper content-type or messes up the url, then the Certified HTTP subsystem shouldn&#039;t be burdened with retrying forever for a message that will never be delivered.  If it receives these status codes, it will raise an exception to the caller and nuke the outgoing request.&lt;br /&gt;
&lt;br /&gt;
* 400 Bad Request&lt;br /&gt;
* 401 Unauthorized&lt;br /&gt;
* 402 Payment Required&lt;br /&gt;
* 403 Forbidden&lt;br /&gt;
* 410 Gone&lt;br /&gt;
* 411 Length Required&lt;br /&gt;
* 413 Request Entity Too Large (if no Retry-After header present)&lt;br /&gt;
* 414 Request-URI Too Long&lt;br /&gt;
* 415 Unsupported Media Type&lt;br /&gt;
* 416 Requested Range Not Satisfiable&lt;br /&gt;
* 417 Expectation Failed&lt;br /&gt;
* 501 Not Implemented&lt;br /&gt;
* 505 HTTP Version Not Supported&lt;br /&gt;
&lt;br /&gt;
=== Ambiguous ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s a little ambiguous what to do when the client gets one of these status codes, so we think that the application should decide.  There are a few ways to do that:&lt;br /&gt;
# The client raises an exception with a retry() method that can be caught by the application, and retried if the application determines that the exception represented a temporary failure.&lt;br /&gt;
# The application passes a list to the Certified HTTP subsystem that sorts these status codes into &#039;retry&#039; or &#039;fail&#039;.&lt;br /&gt;
# The subsystem uses a heuristic such as retrying for a short period of time then converting to a Fail if still not successful.&lt;br /&gt;
Here&#039;s the list of status codes:&lt;br /&gt;
&lt;br /&gt;
* 303 See Other (retry will use GET even if original used POST)&lt;br /&gt;
* 307 Temporary Redirect (only if POST)&lt;br /&gt;
* 404 Not Found&lt;br /&gt;
* 406 Not Acceptable&lt;br /&gt;
* 407 Proxy Authentication Required&lt;br /&gt;
* 409 Conflict&lt;br /&gt;
* 412 Precondition Failed&lt;br /&gt;
* 500 Internal Server Error&lt;br /&gt;
&lt;br /&gt;
= Related Technologies =&lt;br /&gt;
I believe that all competitors to this fall into one of three categories, specialized message queues, reliable logic tunneled through HTTP, and delivery over HTTP with setup charges.&lt;br /&gt;
&lt;br /&gt;
== traditional message queue technology ==&lt;br /&gt;
This includes products like [http://www-306.ibm.com/software/integration/wmq/ MQ], [http://www.microsoft.com/windowsserver2003/technologies/msmq/default.mspx MSMQ], and [http://activemq.apache.org/ ActiveMQ].&lt;br /&gt;
&lt;br /&gt;
These technologies are useful, but provide a number of hurdles:&lt;br /&gt;
* No common standards.&lt;br /&gt;
* Integrates a new technology with unknown performance characteristics.&lt;br /&gt;
* Requires significant operational overhead.&lt;br /&gt;
&lt;br /&gt;
Because of this, we have opted to use HTTP as a foundation of the technology.&lt;br /&gt;
&lt;br /&gt;
== reliable application logic in body ==&lt;br /&gt;
This includes technologies like [http://www.ibm.com/developerworks/library/ws-httprspec/ httpr] and [http://www.ibm.com/developerworks/library/specification/ws-rm/ ws-reliable].&lt;br /&gt;
&lt;br /&gt;
These tend to be thoroughly engineered protocol specifications which regrettably repeat the mistakes of the nearly defunct XMLRPC and the soon to join it SOAP -- namely, treating services as a function call. This is a reasonable approach, and is probably the most obvious to the engineers working on the problem. The most obvious path, which is followed in both of the examples, is to package a traditional message queue body into an HTTP body sent via POST. Treating web services as function calls severely limits the expressive nature of HTTP and should be avoided.&lt;br /&gt;
&lt;br /&gt;
Consumers of web services prefer REST APIs rather than function calls over HTTP. I believe this is because REST is inherently more comprehensible to consumers since all of the data is data the consumer requested. In one telling data point, Amazon has both SOAP and REST interfaces to their web services, and 85% of their usage is of the REST interface[http://www.oreillynet.com/pub/wlg/3005]. I believe ceding power to the consumer is the only path to make wide adoption possible. In doing so, we must drop the entire concept of burying data the consumer wants inside application data.&lt;br /&gt;
&lt;br /&gt;
== reliable delivery after setup ==&lt;br /&gt;
There appear to be a few proposals of this nature around the web and a shining example can be found in [http://www.dehora.net/doc/httplr/draft-httplr-01.html httplr].&lt;br /&gt;
&lt;br /&gt;
These are http reliability mechanisms which require a round trip to begin the reliable transfer and then follow through with some permutation of acknowledging the transfer. This setup can be cheap since the setup does not have the same reliability constraints as long as all clients correctly handle 404. Also, some of this overhead can be optimized away by batching the setup requests.&lt;br /&gt;
&lt;br /&gt;
However, a protocol which requires setup for all messaging will always be more expensive than other options.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Certified_HTTP&amp;diff=42468</id>
		<title>Certified HTTP</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Certified_HTTP&amp;diff=42468"/>
		<updated>2007-11-30T18:19:15Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* X-Message-ID */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Goals =&lt;br /&gt;
The basic goal of Certified HTTP (colloquially known as chttp) is to perform exactly-once messaging between two hosts.&lt;br /&gt;
&lt;br /&gt;
From a standard http client perspective, if the client reads a whole response, then it knows for certain the server handled the request. However, for all other failure modes, the client can&#039;t be sure if the server did, or did-not perform the request function. On the server side, the server can never know if the client ever got the answer or not. For some operations, we need the ability for the client to perform a data-altering operation and be insistent that it occur. In particular, if it isn&#039;t certain that it happened, then it must be able to try again safely.&lt;br /&gt;
&lt;br /&gt;
The bigger picture goal is to make a simple way to conduct reliable delivery and receipt such that general adoption by the wider community is possible. This means that we have to respect HTTP where we can to take advantage of existing tools and methodology and to never contradict common conventions in a REST world.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Join the [https://lists.secondlife.com/cgi-bin/mailman/listinfo/chttpdev mailing list].&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Workflow =&lt;br /&gt;
&lt;br /&gt;
The workflow is a specification/pseudocode for what actions both ends of chttp communication need to take to fulfill the requirements.&lt;br /&gt;
&lt;br /&gt;
== Interaction Sequence ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a diagram that describes an everything-works certified http communication.&lt;br /&gt;
&lt;br /&gt;
[[Image:Interaction_sequence.png]]&lt;br /&gt;
&lt;br /&gt;
Of note are the failure points.  These are the effective crash locations of the participants (the failure points on the arrows represent communication failures).  Actions that intervene between two failure points should be deterministic and/or atomic enough that a crash occurring midway through them is functionally identical to a crash occurring at the immediately prior failure point.&lt;br /&gt;
&lt;br /&gt;
The [[Certified HTTP Failure Diagrams]] page (warning: &#039;&#039;&#039;very&#039;&#039;&#039; image-heavy) has a relatively-exhaustive exploration of the way a Certified HTTP implementation should behave in the face of failures.&lt;br /&gt;
&lt;br /&gt;
== Sending a Message ==&lt;br /&gt;
&lt;br /&gt;
The sending-side API looks very much like a normal HTTP method call:&lt;br /&gt;
  response = certified_http.put(url, body)&lt;br /&gt;
&lt;br /&gt;
What happens under the covers is:&lt;br /&gt;
# Generate a globally unique message ID for the message&lt;br /&gt;
# Store the outgoing request (headers and all), including the message id, in a durable store &amp;quot;outbox&amp;quot;, and waits for a response.&lt;br /&gt;
# A potentially asynchronous process performs the following steps:&lt;br /&gt;
## Retrieves the request from the outbox.&lt;br /&gt;
## Performs the HTTP request specified by the outbox request and waits for a response.&lt;br /&gt;
## If a response is not forthcoming, for whatever reason, the process retries after a certain period.&lt;br /&gt;
## If the server sends an error code that indicates that the reliable message will never complete (e.g. 501), or a long timeout expires indicating that an absurd amount of time has elapsed, the method throws an exception.&lt;br /&gt;
# Opens a transaction on the durable store&lt;br /&gt;
# Stores the incoming response in a durable inbox.&lt;br /&gt;
# &#039;Tombstones&#039; the message in the outbox, which essentially marks the message as having been received, so that if the application resumes again, it doesn&#039;t resend.&lt;br /&gt;
# Closes the transaction on the durable store&lt;br /&gt;
# If the response contains a header indicating a confirmation url on the recipient, performs an HTTP DELETE on the resource to ack the incoming message.&lt;br /&gt;
&lt;br /&gt;
There are no explicit semantics for the response body, like HTTP itself.  The content will vary depending on the application.&lt;br /&gt;
&lt;br /&gt;
== Receiving a Message ==&lt;br /&gt;
&lt;br /&gt;
The receiver sets up a node in the url hierarchy, just like a regular http node.  When an incoming request comes in, the receiver:&lt;br /&gt;
&lt;br /&gt;
# Stores the incoming request in a durable store &amp;quot;inbox&amp;quot;, if it doesn&#039;t already contain a message with the same ID.&lt;br /&gt;
# A potentially asynchronous process performs the following steps:&lt;br /&gt;
## Looks for responses in the outbox matching the incoming message id, and if it finds one, sends it as the response without invoking anything else.&lt;br /&gt;
## Opens a transaction on the database, locking the inbox request&lt;br /&gt;
## Calls the handler method on the receiving node:&lt;br /&gt;
### &amp;lt;code&amp;gt;def handle_put(body, txn):&amp;lt;br/&amp;gt;return &amp;quot;My Response&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
### The handler method can use the open transaction to perform actions in the database that are atomic with the receipt of the message.  Any non-idempotent operation must be done atomically in this way.&lt;br /&gt;
## Stores the return value of the handle method as an outgoing response in the outbox, without closing the transaction. &lt;br /&gt;
## Removes the incoming request from the inbox&lt;br /&gt;
## Closes the transaction&lt;br /&gt;
# Discovers a new item in the outbox, responds to the incoming http request with the response from the outbox, including a url that, if DELETEd, will remove the item from the outbox.&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
&lt;br /&gt;
We have the concept of a &amp;quot;long&amp;quot; time (LT).  The purpose of this time is to ensure that any clients will stop trying a particular request long before the server discards state associated with the request.  This is not a very theoretically &amp;quot;pure&amp;quot; concept, since it relies on all parties conforming to certain (reasonable) assumptions, but we believe that we get significant benefits (lack of explicit negotiation), at little risk of actually entering an incorrect state.   chttp is expected to generate a small amount of bookkeeping data for each message, and there needs to be a way to expire this data in a way that doesn&#039;t involve additional negotiation between servers and clients.  The server should keep data for LT, and clients should not retry messages that are older than LT/2 or similar, so that there is at least LT/2 for a Reliable Host to recover from errors, and LT/2 for clock skew.  LT therefore should be orders of magnitude longer than the longest downtime we expect to see in the system and the largest clock skew we expect to see.  Off the cuff, 30 days seems like a reasonable value for LT.&lt;br /&gt;
&lt;br /&gt;
* chttp is based on http, and can use any facility provided by http 1.1 where not otherwise contradicted.&lt;br /&gt;
** this includes the use of https, pipelining, chunked encoding, proxies, redirects, caches, and headers such as Accept, Accept-Encoding, Expect, and Content-Type.&lt;br /&gt;
** any normal http verb appropriate to context should be accepted, eg POST, PUT, GET, DELETE&lt;br /&gt;
** unless otherwise specified, the http feature set in use is orthogonal and effectively transparent to chttp&lt;br /&gt;
* in any complete chttp exchange the client and server can eventually agree on success or failure of delivery, though it is more important that no ill effects arise when they disagree&lt;br /&gt;
* any message will be effectively received once and only once or not at all&lt;br /&gt;
* the content of the http body must be opaque to chttp&lt;br /&gt;
* the URI of the original request must be opaque to chttp&lt;br /&gt;
* chttp enabled clients and servers can integrate with unreliable tools&lt;br /&gt;
** the chttp server can differentiate reliable requests and respond without reliability guarantees (i.e. act as a normal http server)&lt;br /&gt;
** chttp clients can differentiate reliable responses and handle unreliable servers (i.e. act as a normal http client)&lt;br /&gt;
* the client will persist the local time of sending&lt;br /&gt;
* if there is one the client must either have the persisted outgoing body or the exact same body can be regenerated on the fly&lt;br /&gt;
* the server will persist the local time of message receipt&lt;br /&gt;
* the server must persist the response body or have a mechanism to idempotently generate the same response to the same request&lt;br /&gt;
* all urls with a chttp server behind them are effectively idempotent for all uniquely identified messages&lt;br /&gt;
** the client can retry steadily over a period of LT/2 days&lt;br /&gt;
** the client and server are assumed to almost always be running&lt;br /&gt;
** over that window of opportunity, the same message will always get the same response&lt;br /&gt;
* all persisted data on a single host is ACID&lt;br /&gt;
&lt;br /&gt;
== requirements on top of http ==&lt;br /&gt;
* if the body of the request is non-zero length, the client MUST include a Content-Length header, unless prohibited by section 4.4 of [http://www.w3.org/Protocols/rfc2616/rfc2616.html RFC 2616]&lt;br /&gt;
** the server will look for \r\n\r\n and content length body to consider the request complete&lt;br /&gt;
** an incomplete request will result in 4XX status code&lt;br /&gt;
* if the body of the response is non-zero length, the server must include a Content-Length header&lt;br /&gt;
** the client will look for \r\n\r\n and content length body to consider the response complete&lt;br /&gt;
** the client will retry on an incomplete response&lt;br /&gt;
* Messages can not be terminated by closing the connection -- only positive expressions of message termination (such as Content-Length) can guarantee that a full message is received.&lt;br /&gt;
&lt;br /&gt;
== assumptions ==&lt;br /&gt;
&lt;br /&gt;
* The client and server will not have any significant time discontinuity, i.e., the clock difference between them should be less than LT/100.&lt;br /&gt;
* The client and server will not have clock drift more than LT/100 per day.&lt;br /&gt;
* Both parties exchanging messages are Reliable Hosts (defined below).&lt;br /&gt;
* Generating a globally unique message ID is inexpensive.&lt;br /&gt;
* It is possible to store a large amount of &#039;small&#039; data (such as [[UUID]]s, urls, and date/timestamps) for LT.  &amp;quot;Large&amp;quot; in this case means &amp;quot;as many items as the throughput of a host implies that you could create during LT&amp;quot;.  In other words, storing this small data will never be a resource problem.&lt;br /&gt;
* Any transaction or data handled by this system will become useless well before LT has elapsed.  &lt;br /&gt;
&lt;br /&gt;
; Reliable Host : A reliable host has the following properties:&lt;br /&gt;
* The host has a durable data store of finite size, which can store data in such a way that it is guaranteed to be recoverable even in the face of a certain number of hardware failures.&lt;br /&gt;
* The host will not be down forever.  Either a clone will be brought up on different hardware, or the machine itself will reappear within a day or so. &lt;br /&gt;
* The host can perform {{Wikipedia|ACID|w=n}} operations on the data it contains.&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
Requiring an opaque body and URI pretty much requires either negotiating an URL beforehand or adding new headers. Since the former was discarded earlier (reliable delivery after setup), we will focus on adding request and response headers.&lt;br /&gt;
&lt;br /&gt;
This is a suggested implementation:&lt;br /&gt;
# chttp enabled servers will behave idempotently with a unique message id on the request&lt;br /&gt;
# the server can request acknowledgment from the client if the request consumes server resources&lt;br /&gt;
&lt;br /&gt;
== Request ==&lt;br /&gt;
A client will start a reliable message with a GET, POST, or PUT to an url on a reliable http server. The url may be known in advance or returned as part of an earlier application protocol exchange. The message itself will be uniquely identified by a new header for the message id.&lt;br /&gt;
&lt;br /&gt;
=== X-Message-ID ===&lt;br /&gt;
A combination of client host identifier with a uuid or sequence number which specifies the reliability client ID for the request. When a server detects the X-Message-ID, it can guarantee reliable message delivery.&lt;br /&gt;
&lt;br /&gt;
Since the message id must be unique, implementations should generate an id of the form &amp;lt;nowiki&amp;gt;$random_uuid@$client_host&amp;lt;/nowiki&amp;gt; where the uuid is from a cryptographically secure generator and client_host is the name of the host.&lt;br /&gt;
&lt;br /&gt;
Sending a message with the same message id but a a different body has an undefined result.&lt;br /&gt;
&lt;br /&gt;
Sending a message with the same message id but with a different header which implies a different response body, eg, the first request specifies &amp;quot;Accept: text/plain&amp;quot; and the second request specifies &amp;quot;Accept: text/html&amp;quot;, the response can be any one of:&lt;br /&gt;
&lt;br /&gt;
* The original response.&lt;br /&gt;
* A transcoded response conforming to the new headers.&lt;br /&gt;
* A 4xx indicating that the server has detected the incompatability&lt;br /&gt;
* A 5xx indicating failure to transcode the original response.&lt;br /&gt;
&lt;br /&gt;
== Response ==&lt;br /&gt;
Generally, when the client gets the 2XX back from the server, the message has been delivered. If the server has a response body, then the client will need to acknowledge receipt of the entire body. If the entire body is not read, the client can safely resubmit the exact same request. The server will include a message url in the headers if the client specified a message id on request and the body requires persistence by the server.&lt;br /&gt;
&lt;br /&gt;
=== X-Message-URL ===&lt;br /&gt;
This will be a unique url on the server for the client message id which the client will DELETE upon receipt of the entire response to the request. This will only exist if there is a non-null response body or the server is consuming significant resources to maintain that url. When the client performs the delete, the server can flush all persisted resources other than the fact that the message was sent at some point.&lt;br /&gt;
&lt;br /&gt;
If the client performs a GET to the message url prior to DELETE, the server must return the same body as the original response, including the X-Message-URL.&lt;br /&gt;
&lt;br /&gt;
== Status Codes ==&lt;br /&gt;
&lt;br /&gt;
The semantics of Certified HTTP are to retry until the message goes through.  HTTP status codes provide one way of determining whether the message made it or not;  we&#039;ve grouped these status codes into &#039;success&#039; or &#039;retry&#039;.   In many cases they can signify that the client is attempting to send an invalid message, an error in the application logic; these are labeled as &#039;fail&#039;.  There is a third class, where the status code may be ambiguous; e.g. 404, which is often emitted by temporarily-misconfigured webservers, but may also indicate that an incorrect url was chosen.&lt;br /&gt;
&lt;br /&gt;
=== Success ===&lt;br /&gt;
&lt;br /&gt;
These status codes, when received, give the client permission to do whatever cleanup it needs to do, and to return to caller, safe in the assumption that the message was delivered.&lt;br /&gt;
&lt;br /&gt;
* 200 OK&lt;br /&gt;
* 201 Created&lt;br /&gt;
* 203 Non-Authoritative Information&lt;br /&gt;
* 204 No Content&lt;br /&gt;
* 205 Reset Content&lt;br /&gt;
* 206 Partial Content&lt;br /&gt;
* 304 Not Modified&lt;br /&gt;
&lt;br /&gt;
=== Retry ===&lt;br /&gt;
&lt;br /&gt;
These status codes indicate a temporary failure or misconfiguration on the server side, and therefore the client should retry until it gets something different.  All the redirected/proxied messages carry the same message-id.&lt;br /&gt;
&lt;br /&gt;
* 202 Accepted (potentially delaying longer than normal)&lt;br /&gt;
* 300 Multiple Choices (follow redirect)&lt;br /&gt;
* 302 Found (follow redirect)&lt;br /&gt;
* 305 Use Proxy (use proxy)&lt;br /&gt;
* 307 Temporary Redirect (follow redirect only if GET)&lt;br /&gt;
* 408 Request Timeout&lt;br /&gt;
* 413 Request Entity Too Large (if Retry-After header present)&lt;br /&gt;
* 502 Bad Gateway&lt;br /&gt;
* 503 Service Unavailable&lt;br /&gt;
* 504 Gateway Timeout&lt;br /&gt;
&lt;br /&gt;
=== Fail ===&lt;br /&gt;
&lt;br /&gt;
If your application logic screws up and picks an improper content-type or messes up the url, then the Certified HTTP subsystem shouldn&#039;t be burdened with retrying forever for a message that will never be delivered.  If it receives these status codes, it will raise an exception to the caller and nuke the outgoing request.&lt;br /&gt;
&lt;br /&gt;
* 400 Bad Request&lt;br /&gt;
* 401 Unauthorized&lt;br /&gt;
* 402 Payment Required&lt;br /&gt;
* 403 Forbidden&lt;br /&gt;
* 410 Gone&lt;br /&gt;
* 411 Length Required&lt;br /&gt;
* 413 Request Entity Too Large (if no Retry-After header present)&lt;br /&gt;
* 414 Request-URI Too Long&lt;br /&gt;
* 415 Unsupported Media Type&lt;br /&gt;
* 416 Requested Range Not Satisfiable&lt;br /&gt;
* 417 Expectation Failed&lt;br /&gt;
* 501 Not Implemented&lt;br /&gt;
* 505 HTTP Version Not Supported&lt;br /&gt;
&lt;br /&gt;
=== Ambiguous ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s a little ambiguous what to do when the client gets one of these status codes, so we think that the application should decide.  There are a few ways to do that:&lt;br /&gt;
# The client raises an exception with a retry() method that can be caught by the application, and retried if the application determines that the exception represented a temporary failure.&lt;br /&gt;
# The application passes a list to the Certified HTTP subsystem that sorts these status codes into &#039;retry&#039; or &#039;fail&#039;.&lt;br /&gt;
# The subsystem uses a heuristic such as retrying for a short period of time then converting to a Fail if still not successful.&lt;br /&gt;
Here&#039;s the list of status codes:&lt;br /&gt;
&lt;br /&gt;
* 303 See Other (retry will use GET even if original used POST)&lt;br /&gt;
* 307 Temporary Redirect (only if POST)&lt;br /&gt;
* 404 Not Found&lt;br /&gt;
* 406 Not Acceptable&lt;br /&gt;
* 407 Proxy Authentication Required&lt;br /&gt;
* 409 Conflict&lt;br /&gt;
* 412 Precondition Failed&lt;br /&gt;
* 500 Internal Server Error&lt;br /&gt;
&lt;br /&gt;
= Related Technologies =&lt;br /&gt;
I believe that all competitors to this fall into one of three categories, specialized message queues, reliable logic tunneled through HTTP, and delivery over HTTP with setup charges.&lt;br /&gt;
&lt;br /&gt;
== traditional message queue technology ==&lt;br /&gt;
This includes products like [http://www-306.ibm.com/software/integration/wmq/ MQ], [http://www.microsoft.com/windowsserver2003/technologies/msmq/default.mspx MSMQ], and [http://activemq.apache.org/ ActiveMQ].&lt;br /&gt;
&lt;br /&gt;
These technologies are useful, but provide a number of hurdles:&lt;br /&gt;
* No common standards.&lt;br /&gt;
* Integrates a new technology with unknown performance characteristics.&lt;br /&gt;
* Requires significant operational overhead.&lt;br /&gt;
&lt;br /&gt;
Because of this, we have opted to use HTTP as a foundation of the technology.&lt;br /&gt;
&lt;br /&gt;
== reliable application logic in body ==&lt;br /&gt;
This includes technologies like [http://www.ibm.com/developerworks/library/ws-httprspec/ httpr] and [http://www.ibm.com/developerworks/library/specification/ws-rm/ ws-reliable].&lt;br /&gt;
&lt;br /&gt;
These tend to be thoroughly engineered protocol specifications which regrettably repeat the mistakes of the nearly defunct XMLRPC and the soon to join it SOAP -- namely, treating services as a function call. This is a reasonable approach, and is probably the most obvious to the engineers working on the problem. The most obvious path, which is followed in both of the examples, is to package a traditional message queue body into an HTTP body sent via POST. Treating web services as function calls severely limits the expressive nature of HTTP and should be avoided.&lt;br /&gt;
&lt;br /&gt;
Consumers of web services prefer REST APIs rather than function calls over HTTP. I believe this is because REST is inherently more comprehensible to consumers since all of the data is data the consumer requested. In one telling data point, Amazon has both SOAP and REST interfaces to their web services, and 85% of their usage is of the REST interface[http://www.oreillynet.com/pub/wlg/3005]. I believe ceding power to the consumer is the only path to make wide adoption possible. In doing so, we must drop the entire concept of burying data the consumer wants inside application data.&lt;br /&gt;
&lt;br /&gt;
== reliable delivery after setup ==&lt;br /&gt;
There appear to be a few proposals of this nature around the web and a shining example can be found in [http://www.dehora.net/doc/httplr/draft-httplr-01.html httplr].&lt;br /&gt;
&lt;br /&gt;
These are http reliability mechanisms which require a round trip to begin the reliable transfer and then follow through with some permutation of acknowledging the transfer. This setup can be cheap since the setup does not have the same reliability constraints as long as all clients correctly handle 404. Also, some of this overhead can be optimized away by batching the setup requests.&lt;br /&gt;
&lt;br /&gt;
However, a protocol which requires setup for all messaging will always be more expensive than other options.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Certified_HTTP&amp;diff=42304</id>
		<title>Certified HTTP</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Certified_HTTP&amp;diff=42304"/>
		<updated>2007-11-29T18:01:37Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* Request */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Goals =&lt;br /&gt;
The basic goal of Certified HTTP (colloquially known as chttp) is to perform exactly-once messaging between two hosts.&lt;br /&gt;
&lt;br /&gt;
From a standard http client perspective, if the client reads a whole response, then it knows for certain the server handled the request. However, for all other failure modes, the client can&#039;t be sure if the server did, or did-not perform the request function. On the server side, the server can never know if the client ever got the answer or not. For some operations, we need the ability for the client to perform a data-altering operation and be insistent that it occur. In particular, if it isn&#039;t certain that it happened, then it must be able to try again safely.&lt;br /&gt;
&lt;br /&gt;
The bigger picture goal is to make a simple way to conduct reliable delivery and receipt such that general adoption by the wider community is possible. This means that we have to respect HTTP where we can to take advantage of existing tools and methodology and to never contradict common conventions in a REST world.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Join the [https://lists.secondlife.com/cgi-bin/mailman/listinfo/chttpdev mailing list].&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
= Workflow =&lt;br /&gt;
&lt;br /&gt;
The workflow is a specification/pseudocode for what actions both ends of chttp communication need to take to fulfill the requirements.&lt;br /&gt;
&lt;br /&gt;
== Interaction Sequence ==&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a diagram that describes an everything-works certified http communication.&lt;br /&gt;
&lt;br /&gt;
[[Image:Interaction_sequence.png]]&lt;br /&gt;
&lt;br /&gt;
Of note are the failure points.  These are the effective crash locations of the participants (the failure points on the arrows represent communication failures).  Actions that intervene between two failure points should be deterministic and/or atomic enough that a crash occurring midway through them is functionally identical to a crash occurring at the immediately prior failure point.&lt;br /&gt;
&lt;br /&gt;
The [[Certified HTTP Failure Diagrams]] page (warning: &#039;&#039;&#039;very&#039;&#039;&#039; image-heavy) has a relatively-exhaustive exploration of the way a Certified HTTP implementation should behave in the face of failures.&lt;br /&gt;
&lt;br /&gt;
== Sending a Message ==&lt;br /&gt;
&lt;br /&gt;
The sending-side API looks very much like a normal HTTP method call:&lt;br /&gt;
  response = certified_http.put(url, body)&lt;br /&gt;
&lt;br /&gt;
What happens under the covers is:&lt;br /&gt;
# Generate a globally unique message ID for the message&lt;br /&gt;
# Store the outgoing request (headers and all), including the message id, in a durable store &amp;quot;outbox&amp;quot;, and waits for a response.&lt;br /&gt;
# A potentially asynchronous process performs the following steps:&lt;br /&gt;
## Retrieves the request from the outbox.&lt;br /&gt;
## Performs the HTTP request specified by the outbox request and waits for a response.&lt;br /&gt;
## If a response is not forthcoming, for whatever reason, the process retries after a certain period.&lt;br /&gt;
## If the server sends an error code that indicates that the reliable message will never complete (e.g. 501), or a long timeout expires indicating that an absurd amount of time has elapsed, the method throws an exception.&lt;br /&gt;
# Opens a transaction on the durable store&lt;br /&gt;
# Stores the incoming response in a durable inbox.&lt;br /&gt;
# &#039;Tombstones&#039; the message in the outbox, which essentially marks the message as having been received, so that if the application resumes again, it doesn&#039;t resend.&lt;br /&gt;
# Closes the transaction on the durable store&lt;br /&gt;
# If the response contains a header indicating a confirmation url on the recipient, performs an HTTP DELETE on the resource to ack the incoming message.&lt;br /&gt;
&lt;br /&gt;
There are no explicit semantics for the response body, like HTTP itself.  The content will vary depending on the application.&lt;br /&gt;
&lt;br /&gt;
== Receiving a Message ==&lt;br /&gt;
&lt;br /&gt;
The receiver sets up a node in the url hierarchy, just like a regular http node.  When an incoming request comes in, the receiver:&lt;br /&gt;
&lt;br /&gt;
# Stores the incoming request in a durable store &amp;quot;inbox&amp;quot;, if it doesn&#039;t already contain a message with the same ID.&lt;br /&gt;
# A potentially asynchronous process performs the following steps:&lt;br /&gt;
## Looks for responses in the outbox matching the incoming message id, and if it finds one, sends it as the response without invoking anything else.&lt;br /&gt;
## Opens a transaction on the database, locking the inbox request&lt;br /&gt;
## Calls the handler method on the receiving node:&lt;br /&gt;
### &amp;lt;code&amp;gt;def handle_put(body, txn):&amp;lt;br/&amp;gt;return &amp;quot;My Response&amp;quot;&amp;lt;/code&amp;gt;&lt;br /&gt;
### The handler method can use the open transaction to perform actions in the database that are atomic with the receipt of the message.  Any non-idempotent operation must be done atomically in this way.&lt;br /&gt;
## Stores the return value of the handle method as an outgoing response in the outbox, without closing the transaction. &lt;br /&gt;
## Removes the incoming request from the inbox&lt;br /&gt;
## Closes the transaction&lt;br /&gt;
# Discovers a new item in the outbox, responds to the incoming http request with the response from the outbox, including a url that, if DELETEd, will remove the item from the outbox.&lt;br /&gt;
&lt;br /&gt;
= Requirements =&lt;br /&gt;
&lt;br /&gt;
We have the concept of a &amp;quot;long&amp;quot; time (LT).  The purpose of this time is to ensure that any clients will stop trying a particular request long before the server discards state associated with the request.  This is not a very theoretically &amp;quot;pure&amp;quot; concept, since it relies on all parties conforming to certain (reasonable) assumptions, but we believe that we get significant benefits (lack of explicit negotiation), at little risk of actually entering an incorrect state.   chttp is expected to generate a small amount of bookkeeping data for each message, and there needs to be a way to expire this data in a way that doesn&#039;t involve additional negotiation between servers and clients.  The server should keep data for LT, and clients should not retry messages that are older than LT/2 or similar, so that there is at least LT/2 for a Reliable Host to recover from errors, and LT/2 for clock skew.  LT therefore should be orders of magnitude longer than the longest downtime we expect to see in the system and the largest clock skew we expect to see.  Off the cuff, 30 days seems like a reasonable value for LT.&lt;br /&gt;
&lt;br /&gt;
* chttp is based on http, and can use any facility provided by http 1.1 where not otherwise contradicted.&lt;br /&gt;
** this includes the use of https, pipelining, chunked encoding, proxies, redirects, caches, and headers such as Accept, Accept-Encoding, Expect, and Content-Type.&lt;br /&gt;
** any normal http verb appropriate to context should be accepted, eg POST, PUT, GET, DELETE&lt;br /&gt;
** unless otherwise specified, the http feature set in use is orthogonal and effectively transparent to chttp&lt;br /&gt;
* in any complete chttp exchange the client and server can eventually agree on success or failure of delivery, though it is more important that no ill effects arise when they disagree&lt;br /&gt;
* any message will be effectively received once and only once or not at all&lt;br /&gt;
* the content of the http body must be opaque to chttp&lt;br /&gt;
* the URI of the original request must be opaque to chttp&lt;br /&gt;
* chttp enabled clients and servers can integrate with unreliable tools&lt;br /&gt;
** the chttp server can differentiate reliable requests and respond without reliability guarantees (i.e. act as a normal http server)&lt;br /&gt;
** chttp clients can differentiate reliable responses and handle unreliable servers (i.e. act as a normal http client)&lt;br /&gt;
* the client will persist the local time of sending&lt;br /&gt;
* if there is one the client must either have the persisted outgoing body or the exact same body can be regenerated on the fly&lt;br /&gt;
* the server will persist the local time of message receipt&lt;br /&gt;
* the server must persist the response body or have a mechanism to idempotently generate the same response to the same request&lt;br /&gt;
* all urls with a chttp server behind them are effectively idempotent for all uniquely identified messages&lt;br /&gt;
** the client can retry steadily over a period of LT/2 days&lt;br /&gt;
** the client and server are assumed to almost always be running&lt;br /&gt;
** over that window of opportunity, the same message will always get the same response&lt;br /&gt;
* all persisted data on a single host is ACID&lt;br /&gt;
&lt;br /&gt;
== requirements on top of http ==&lt;br /&gt;
* if the body of the request is non-zero length, the client MUST include a Content-Length header, unless prohibited by section 4.4 of [http://www.w3.org/Protocols/rfc2616/rfc2616.html RFC 2616]&lt;br /&gt;
** the server will look for \r\n\r\n and content length body to consider the request complete&lt;br /&gt;
** an incomplete request will result in 4XX status code&lt;br /&gt;
* if the body of the response is non-zero length, the server must include a Content-Length header&lt;br /&gt;
** the client will look for \r\n\r\n and content length body to consider the response complete&lt;br /&gt;
** the client will retry on an incomplete response&lt;br /&gt;
* Messages can not be terminated by closing the connection -- only positive expressions of message termination (such as Content-Length) can guarantee that a full message is received.&lt;br /&gt;
&lt;br /&gt;
== assumptions ==&lt;br /&gt;
&lt;br /&gt;
* The client and server will not have any significant time discontinuity, i.e., the clock difference between them should be less than LT/100.&lt;br /&gt;
* The client and server will not have clock drift more than LT/100 per day.&lt;br /&gt;
* Both parties exchanging messages are Reliable Hosts (defined below).&lt;br /&gt;
* Generating a globally unique message ID is inexpensive.&lt;br /&gt;
* It is possible to store a large amount of &#039;small&#039; data (such as [[UUID]]s, urls, and date/timestamps) for LT.  &amp;quot;Large&amp;quot; in this case means &amp;quot;as many items as the throughput of a host implies that you could create during LT&amp;quot;.  In other words, storing this small data will never be a resource problem.&lt;br /&gt;
* Any transaction or data handled by this system will become useless well before LT has elapsed.  &lt;br /&gt;
&lt;br /&gt;
; Reliable Host : A reliable host has the following properties:&lt;br /&gt;
* The host has a durable data store of finite size, which can store data in such a way that it is guaranteed to be recoverable even in the face of a certain number of hardware failures.&lt;br /&gt;
* The host will not be down forever.  Either a clone will be brought up on different hardware, or the machine itself will reappear within a day or so. &lt;br /&gt;
* The host can perform {{Wikipedia|ACID|w=n}} operations on the data it contains.&lt;br /&gt;
&lt;br /&gt;
= Implementation =&lt;br /&gt;
Requiring an opaque body and URI pretty much requires either negotiating an URL beforehand or adding new headers. Since the former was discarded earlier (reliable delivery after setup), we will focus on adding request and response headers.&lt;br /&gt;
&lt;br /&gt;
This is a suggested implementation:&lt;br /&gt;
# chttp enabled servers will behave idempotently with a unique message id on the request&lt;br /&gt;
# the server can request acknowledgment from the client if the request consumes server resources&lt;br /&gt;
&lt;br /&gt;
== Request ==&lt;br /&gt;
A client will start a reliable message with a GET, POST, or PUT to an url on a reliable http server. The url may be known in advance or returned as part of an earlier application protocol exchange. The message itself will be uniquely identified by a new header for the message id.&lt;br /&gt;
&lt;br /&gt;
=== X-Message-ID ===&lt;br /&gt;
A combination of client host identifier with a uuid or sequence number which specifies the reliability client ID for the request. When a server detects the X-Message-ID, it can guarantee reliable message delivery.&lt;br /&gt;
&lt;br /&gt;
Since the message id must be unique, implementations should generate an id of the form &amp;lt;nowiki&amp;gt;$random_uuid@$client_host&amp;lt;/nowiki&amp;gt; where the uuid is from a cryptographically secure generator and client_host is the name of the host.&lt;br /&gt;
&lt;br /&gt;
Sending a message with the same message id but a a different body has an undefined result.&lt;br /&gt;
&lt;br /&gt;
Sending a message with the same message id but with a different header which implies a different response body, eg, the first request specifies &amp;quot;Accept: text/plain&amp;quot; and the second request specifies &amp;quot;Accept: text/html&amp;quot;, the response is undefined. The server may respond with the original response, a 4xx indicating client error, or even a 5xx if the server attempted but failed to service the equivalent response with a different content body.&lt;br /&gt;
&lt;br /&gt;
== Response ==&lt;br /&gt;
Generally, when the client gets the 2XX back from the server, the message has been delivered. If the server has a response body, then the client will need to acknowledge receipt of the entire body. If the entire body is not read, the client can safely resubmit the exact same request. The server will include a message url in the headers if the client specified a message id on request and the body requires persistence by the server.&lt;br /&gt;
&lt;br /&gt;
=== X-Message-URL ===&lt;br /&gt;
This will be a unique url on the server for the client message id which the client will DELETE upon receipt of the entire response to the request. This will only exist if there is a non-null response body or the server is consuming significant resources to maintain that url. When the client performs the delete, the server can flush all persisted resources other than the fact that the message was sent at some point.&lt;br /&gt;
&lt;br /&gt;
If the client performs a GET to the message url prior to DELETE, the server must return the same body as the original response, including the X-Message-URL.&lt;br /&gt;
&lt;br /&gt;
== Status Codes ==&lt;br /&gt;
&lt;br /&gt;
The semantics of Certified HTTP are to retry until the message goes through.  HTTP status codes provide one way of determining whether the message made it or not;  we&#039;ve grouped these status codes into &#039;success&#039; or &#039;retry&#039;.   In many cases they can signify that the client is attempting to send an invalid message, an error in the application logic; these are labeled as &#039;fail&#039;.  There is a third class, where the status code may be ambiguous; e.g. 404, which is often emitted by temporarily-misconfigured webservers, but may also indicate that an incorrect url was chosen.&lt;br /&gt;
&lt;br /&gt;
=== Success ===&lt;br /&gt;
&lt;br /&gt;
These status codes, when received, give the client permission to do whatever cleanup it needs to do, and to return to caller, safe in the assumption that the message was delivered.&lt;br /&gt;
&lt;br /&gt;
* 200 OK&lt;br /&gt;
* 201 Created&lt;br /&gt;
* 203 Non-Authoritative Information&lt;br /&gt;
* 204 No Content&lt;br /&gt;
* 205 Reset Content&lt;br /&gt;
* 206 Partial Content&lt;br /&gt;
* 304 Not Modified&lt;br /&gt;
&lt;br /&gt;
=== Retry ===&lt;br /&gt;
&lt;br /&gt;
These status codes indicate a temporary failure or misconfiguration on the server side, and therefore the client should retry until it gets something different.  All the redirected/proxied messages carry the same message-id.&lt;br /&gt;
&lt;br /&gt;
* 202 Accepted (potentially delaying longer than normal)&lt;br /&gt;
* 300 Multiple Choices (follow redirect)&lt;br /&gt;
* 302 Found (follow redirect)&lt;br /&gt;
* 305 Use Proxy (use proxy)&lt;br /&gt;
* 307 Temporary Redirect (follow redirect only if GET)&lt;br /&gt;
* 408 Request Timeout&lt;br /&gt;
* 413 Request Entity Too Large (if Retry-After header present)&lt;br /&gt;
* 502 Bad Gateway&lt;br /&gt;
* 503 Service Unavailable&lt;br /&gt;
* 504 Gateway Timeout&lt;br /&gt;
&lt;br /&gt;
=== Fail ===&lt;br /&gt;
&lt;br /&gt;
If your application logic screws up and picks an improper content-type or messes up the url, then the Certified HTTP subsystem shouldn&#039;t be burdened with retrying forever for a message that will never be delivered.  If it receives these status codes, it will raise an exception to the caller and nuke the outgoing request.&lt;br /&gt;
&lt;br /&gt;
* 400 Bad Request&lt;br /&gt;
* 401 Unauthorized&lt;br /&gt;
* 402 Payment Required&lt;br /&gt;
* 403 Forbidden&lt;br /&gt;
* 410 Gone&lt;br /&gt;
* 411 Length Required&lt;br /&gt;
* 413 Request Entity Too Large (if no Retry-After header present)&lt;br /&gt;
* 414 Request-URI Too Long&lt;br /&gt;
* 415 Unsupported Media Type&lt;br /&gt;
* 416 Requested Range Not Satisfiable&lt;br /&gt;
* 417 Expectation Failed&lt;br /&gt;
* 501 Not Implemented&lt;br /&gt;
* 505 HTTP Version Not Supported&lt;br /&gt;
&lt;br /&gt;
=== Ambiguous ===&lt;br /&gt;
&lt;br /&gt;
It&#039;s a little ambiguous what to do when the client gets one of these status codes, so we think that the application should decide.  There are a few ways to do that:&lt;br /&gt;
# The client raises an exception with a retry() method that can be caught by the application, and retried if the application determines that the exception represented a temporary failure.&lt;br /&gt;
# The application passes a list to the Certified HTTP subsystem that sorts these status codes into &#039;retry&#039; or &#039;fail&#039;.&lt;br /&gt;
# The subsystem uses a heuristic such as retrying for a short period of time then converting to a Fail if still not successful.&lt;br /&gt;
Here&#039;s the list of status codes:&lt;br /&gt;
&lt;br /&gt;
* 303 See Other (retry will use GET even if original used POST)&lt;br /&gt;
* 307 Temporary Redirect (only if POST)&lt;br /&gt;
* 404 Not Found&lt;br /&gt;
* 406 Not Acceptable&lt;br /&gt;
* 407 Proxy Authentication Required&lt;br /&gt;
* 409 Conflict&lt;br /&gt;
* 412 Precondition Failed&lt;br /&gt;
* 500 Internal Server Error&lt;br /&gt;
&lt;br /&gt;
= Related Technologies =&lt;br /&gt;
I believe that all competitors to this fall into one of three categories, specialized message queues, reliable logic tunneled through HTTP, and delivery over HTTP with setup charges.&lt;br /&gt;
&lt;br /&gt;
== traditional message queue technology ==&lt;br /&gt;
This includes products like [http://www-306.ibm.com/software/integration/wmq/ MQ], [http://www.microsoft.com/windowsserver2003/technologies/msmq/default.mspx MSMQ], and [http://activemq.apache.org/ ActiveMQ].&lt;br /&gt;
&lt;br /&gt;
These technologies are useful, but provide a number of hurdles:&lt;br /&gt;
* No common standards.&lt;br /&gt;
* Integrates a new technology with unknown performance characteristics.&lt;br /&gt;
* Requires significant operational overhead.&lt;br /&gt;
&lt;br /&gt;
Because of this, we have opted to use HTTP as a foundation of the technology.&lt;br /&gt;
&lt;br /&gt;
== reliable application logic in body ==&lt;br /&gt;
This includes technologies like [http://www.ibm.com/developerworks/library/ws-httprspec/ httpr] and [http://www.ibm.com/developerworks/library/specification/ws-rm/ ws-reliable].&lt;br /&gt;
&lt;br /&gt;
These tend to be thoroughly engineered protocol specifications which regrettably repeat the mistakes of the nearly defunct XMLRPC and the soon to join it SOAP -- namely, treating services as a function call. This is a reasonable approach, and is probably the most obvious to the engineers working on the problem. The most obvious path, which is followed in both of the examples, is to package a traditional message queue body into an HTTP body sent via POST. Treating web services as function calls severely limits the expressive nature of HTTP and should be avoided.&lt;br /&gt;
&lt;br /&gt;
Consumers of web services prefer REST APIs rather than function calls over HTTP. I believe this is because REST is inherently more comprehensible to consumers since all of the data is data the consumer requested. In one telling data point, Amazon has both SOAP and REST interfaces to their web services, and 85% of their usage is of the REST interface[http://www.oreillynet.com/pub/wlg/3005]. I believe ceding power to the consumer is the only path to make wide adoption possible. In doing so, we must drop the entire concept of burying data the consumer wants inside application data.&lt;br /&gt;
&lt;br /&gt;
== reliable delivery after setup ==&lt;br /&gt;
There appear to be a few proposals of this nature around the web and a shining example can be found in [http://www.dehora.net/doc/httplr/draft-httplr-01.html httplr].&lt;br /&gt;
&lt;br /&gt;
These are http reliability mechanisms which require a round trip to begin the reliable transfer and then follow through with some permutation of acknowledging the transfer. This setup can be cheap since the setup does not have the same reliability constraints as long as all clients correctly handle 404. Also, some of this overhead can be optimized away by batching the setup requests.&lt;br /&gt;
&lt;br /&gt;
However, a protocol which requires setup for all messaging will always be more expensive than other options.&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:Certified_HTTP&amp;diff=39049</id>
		<title>Talk:Certified HTTP</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:Certified_HTTP&amp;diff=39049"/>
		<updated>2007-11-04T19:14:26Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* Status Codes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==X-Message-ID==&lt;br /&gt;
&lt;br /&gt;
How about replacing the $random_uuid with an MD5 (or stronger) digest of the message body?  That would eliminate the undefined result of sending a message with the same message id but a a different body.  (Undefined results can be opportunities for exploits.) --[[User:Omei Turnbull|Omei Turnbull]] 20:21, 10 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:That wouldn&#039;t solve the problem, you would still be sending a message with the same message id if you sent two identical messages bodies. You would be guarantying a collision. It is really only an issue if two messages of the same ID are being processed at the same time. I think using $random_uuid is reasonable and in the event of a Message-ID collision or malformed Message-ID have the server return a [http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1 400]. -- [[User:Strife Onizuka|Strife Onizuka]] 00:01, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Heh, looks like Strife and I saw this at the same moment.  :-)  I guess if you digested the entire state of the message, including headers, receiving url, and sending url/host, then you&#039;re only ruling out the case where you do actually want to send two of the exact same message between the same two hosts at the exact same time and have both be processed as independent message.  Thanks for the idea!  [[User:Which Linden|Which Linden]] 00:06, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
==  X-Message-URL ==&lt;br /&gt;
&lt;br /&gt;
:&amp;quot;If the client performs a GET to the message url prior to DELETE, the server must return the same body as the original response, including the X-Message-URL.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
I think this may be an attack point, since it would require the server to cache the response body. There should also be a short timeout on the caching. This requirement makes it look like this protocol isn&#039;t something you want use with unauthorized clients. -- [[User:Strife Onizuka|Strife Onizuka]] 00:18, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::How does this differ from the explicit requirement that &amp;quot;the server must persist the response body or have a mechanism to idempotent generate the same response to the same request&amp;quot;?  But yes, it seems like the need to persist un-acknowledged response bodies for 15 days creates a big opportunity for a DDOS-type attack if reliable messages from unauthenticated clients are allowed. - [[User:Omei_Turnbull|Omei Turnbull]]&lt;br /&gt;
&lt;br /&gt;
::: That would be a problem if it only statically persisted a complete response. If it has a way to generate the idempotent response at any later time, there is no need to statically persist the complete response. [[User:Dzonatas Sol|Dzonatas Sol]] 10:22, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::: The entire response body has to be stored so that if the connection was terminated before the response was received it can be requested by sending a GET to X-Message-URL (instead of a DELETE). -- [[User:Strife Onizuka|Strife Onizuka]] 15:27, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::: That would be one way. There are other ways to generate a response that is idempotent. [[User:Dzonatas Sol|Dzonatas Sol]] 15:49, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::::: True, but it really depends on what is being requested and whether what is wanted is the old status or the current status. -- [[User:Strife Onizuka|Strife Onizuka]] 16:11, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::: Indeed, it depends on the intervals of when data is aggregated or archived. The complexity begins there. [[User:Dzonatas Sol|Dzonatas Sol]] 16:15, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::The issue I see (which I think is the same issue Strife was referring to) is that when the server gets a request, it has to check to see whether it is a duplicate of any outstanding request (i.e. a request for which the response hasn&#039;t been acknowledged) issued within the last 15 days, so that if it is, it will repeat its previous response.  If these requests can come from untrusted clients, the server could purposely be subjected to requests that are not acknowledged, until the server is no longer able to respond to any requests in a timely manner.--[[User:Omei Turnbull|Omei Turnbull]] 12:59, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::Thats what I was thinking. -- [[User:Strife Onizuka|Strife Onizuka]] 15:27, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::: Though there are certain things you could do to stave off DoS attacks like refusing to serve more than N connections at a time and refusing to even open a tcp connection to any future ones, I agree that without further consideration it&#039;s probably not a good idea to do chttp between hosts that don&#039;t trust each other.  [[User:Which Linden|Which Linden]] 21:12, 3 October 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::This could be mitigated by adding a header field in the client message saying whether this is an initial or a follow-up request.  The server would not be required to check initial requests against its history of open requests.  Follow-up requests, which would require a lookup against the open requests, could be done at reduced priority, so that they don&#039;t interfere with normal traffic.--[[User:Omei Turnbull|Omei Turnbull]] 16:43, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::: Wow, how did I not see this earlier?  I think that the problem with this idea is that the client doesn&#039;t, in general, know whether it&#039;s making an initial or a follow up request.  If it hasn&#039;t received a response from the server, it doesn&#039;t know whether the server received the message and didn&#039;t respond, or if the message never made it to the server in the first place (or was incomplete, as would happen if the network died mid-send).  [[User:Which Linden|Which Linden]] 21:12, 3 October 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Thoughts ==&lt;br /&gt;
For a simple setup X-Message-URL could be the original request URL. The DELETE command should send the same X-Message-ID as the orig request to better facilitate this. This would have the added benefit that a client could possibly cancel a request by sending a DELETE before getting a response.&lt;br /&gt;
This doesn&#039;t have to be all that complicated to implement. Once a request comes in, check to see if there is a DB entry for it, if it does not exist in the DB, execute the command and write the body to file and return the body. If it does exist in the DB already, check the status of the request, if there is a body, return it and wait for the timeout or DELETE command before removing the DB entry. -- [[User:Strife Onizuka|Strife Onizuka]] 15:34, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Cleanup ==&lt;br /&gt;
&lt;br /&gt;
Limiting the number of concurrent requests per client is one way of reducing DOS risk but if a client crashes and reconnects then it will need some way of finding out what requests need to be closed. There should probably be some interface the client can query the server to find out what requests it has open. The response to such a query would give URLs to close those requests but they should not be able to return those request&#039;s response bodies as that could be a security breach. Additionally those requests returned should be tagged with the session that created them and the status of that session (so multiple sessions can use the same authorization information concurrently). -- [[User:Strife Onizuka|Strife Onizuka]] 16:24, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:This is a really interesting point.  We&#039;ve given very little thought to communication with untrusted and unreliable clients.  Right now, we are assuming that the client is a reliable service itself -- chttp is essentially a peer protocol between durable hosts.  In particular, we want to assume delivery, which means that all the application logic doesn&#039;t have to contain a lot of failure cases (always a bugbear to write and test). The application just assumes that the message will eventually make it, despite temporary failures on both sending and receiving hosts.  With those assumptions, it&#039;s reasonable to say that the client doesn&#039;t need to query the server to find out what requests it has open.  It&#039;s not clear if the semantics even mean anything if the client is untrusted or unreliable.  [[User:Which Linden|Which Linden]] 22:01, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::Perhaps there needs to be a way of identifing trusted hosts? Perhaps using HTTP authentication on servers that require identity? and if they can be identified, don&#039;t apply a limit to concurrent requests or at least increase the limit? Though this would surely make https as the perfered protocol in such a case, so authentication information is more secure. -- [[User:Nik Woodget|Nik Woodget]] 10:20, 19 September 2007&lt;br /&gt;
&lt;br /&gt;
::: Could use client certificates, too.  I think specifying an authentication method is outside the scope of certified http, though.  [[User:Which Linden|Which Linden]] 21:59, 3 October 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::: As much as possible, things like authentication, should follow existing http style practice. I&#039;d like to see it compose with the related specs. This seems like an overall good principle [[User: Zha Ewry|Zha Ewry]] 12:40 3 October 2007&lt;br /&gt;
&lt;br /&gt;
== Status Codes ==&lt;br /&gt;
&lt;br /&gt;
I suggest should adjust interpretation of a few of the status codes.&lt;br /&gt;
; 304 Not Modified : I believe we should add a requirement that no cHTTP enabled server will return 304 to any request which include x-message-id. In order to maintain idempotence, we should typically return 200, but at least we should return 200 &amp;lt;= status &amp;lt; 300.&lt;br /&gt;
; 203 Non-Authoritative Information : I think we should consider this a success because the use case where this makes sense is if the server has a secondary persistent store which it considers good enough for this particular transaction. It also makes me nervous to think of anything in 2xx other than 202 as a retry.&lt;br /&gt;
; 406 Not Acceptable : Since the persisted client request theoretically includes the Accept header, there is no way that further calls will ever return anything other than 406. So shouldn&#039;t we fail sooner?&lt;br /&gt;
; 411 Length Required : A cHTTP dialogue requires Content-Length for every non-zero length message so this sound like a permanent failure to me.&lt;br /&gt;
&lt;br /&gt;
[[User:Phoenix Linden|Phoenix Linden]] 22:28, 1 November 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Hah, we should have looked at [http://www.ilovejackdaniels.com/apache/http-status-codes-explained/ this page], since it already kinda does the work for us.&lt;br /&gt;
:; 304 : I don&#039;t think it really matters.  If the client wants to add an If-Modified-Since header, why shouldn&#039;t the server accommodate it?  I don&#039;t think there&#039;s a compelling reason to make chttp behave differently than standard http with regards to this status code.&lt;br /&gt;
:; 203 : Agreed.  &lt;br /&gt;
:; 406 : The case where this might be usefully Ambiguous is when a server is temporarily incapacitated or misconfigured and throws 406s until it gets fixed.  Not sure if that&#039;s plausible though.&lt;br /&gt;
:; 411 : Agreed.&lt;br /&gt;
:Thanks for looking these over!  I&#039;m gonna wait for Sardonyx to weigh in before moving stuff around though.&lt;br /&gt;
:[[User:Which Linden|Which Linden]] 23:21, 1 November 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::; 304: Agree.&lt;br /&gt;
::; 406: Maybe. Let&#039;s leave it ambiguous.&lt;br /&gt;
::[[User:Phoenix Linden|Phoenix Linden]] 11:14, 4 November 2007 (PST)&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:Certified_HTTP&amp;diff=38861</id>
		<title>Talk:Certified HTTP</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:Certified_HTTP&amp;diff=38861"/>
		<updated>2007-11-02T05:28:23Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: Status Codes&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==X-Message-ID==&lt;br /&gt;
&lt;br /&gt;
How about replacing the $random_uuid with an MD5 (or stronger) digest of the message body?  That would eliminate the undefined result of sending a message with the same message id but a a different body.  (Undefined results can be opportunities for exploits.) --[[User:Omei Turnbull|Omei Turnbull]] 20:21, 10 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:That wouldn&#039;t solve the problem, you would still be sending a message with the same message id if you sent two identical messages bodies. You would be guarantying a collision. It is really only an issue if two messages of the same ID are being processed at the same time. I think using $random_uuid is reasonable and in the event of a Message-ID collision or malformed Message-ID have the server return a [http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.1 400]. -- [[User:Strife Onizuka|Strife Onizuka]] 00:01, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:Heh, looks like Strife and I saw this at the same moment.  :-)  I guess if you digested the entire state of the message, including headers, receiving url, and sending url/host, then you&#039;re only ruling out the case where you do actually want to send two of the exact same message between the same two hosts at the exact same time and have both be processed as independent message.  Thanks for the idea!  [[User:Which Linden|Which Linden]] 00:06, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
==  X-Message-URL ==&lt;br /&gt;
&lt;br /&gt;
:&amp;quot;If the client performs a GET to the message url prior to DELETE, the server must return the same body as the original response, including the X-Message-URL.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
I think this may be an attack point, since it would require the server to cache the response body. There should also be a short timeout on the caching. This requirement makes it look like this protocol isn&#039;t something you want use with unauthorized clients. -- [[User:Strife Onizuka|Strife Onizuka]] 00:18, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::How does this differ from the explicit requirement that &amp;quot;the server must persist the response body or have a mechanism to idempotent generate the same response to the same request&amp;quot;?  But yes, it seems like the need to persist un-acknowledged response bodies for 15 days creates a big opportunity for a DDOS-type attack if reliable messages from unauthenticated clients are allowed. - [[User:Omei_Turnbull|Omei Turnbull]]&lt;br /&gt;
&lt;br /&gt;
::: That would be a problem if it only statically persisted a complete response. If it has a way to generate the idempotent response at any later time, there is no need to statically persist the complete response. [[User:Dzonatas Sol|Dzonatas Sol]] 10:22, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::: The entire response body has to be stored so that if the connection was terminated before the response was received it can be requested by sending a GET to X-Message-URL (instead of a DELETE). -- [[User:Strife Onizuka|Strife Onizuka]] 15:27, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::: That would be one way. There are other ways to generate a response that is idempotent. [[User:Dzonatas Sol|Dzonatas Sol]] 15:49, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::::: True, but it really depends on what is being requested and whether what is wanted is the old status or the current status. -- [[User:Strife Onizuka|Strife Onizuka]] 16:11, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::::::: Indeed, it depends on the intervals of when data is aggregated or archived. The complexity begins there. [[User:Dzonatas Sol|Dzonatas Sol]] 16:15, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::The issue I see (which I think is the same issue Strife was referring to) is that when the server gets a request, it has to check to see whether it is a duplicate of any outstanding request (i.e. a request for which the response hasn&#039;t been acknowledged) issued within the last 15 days, so that if it is, it will repeat its previous response.  If these requests can come from untrusted clients, the server could purposely be subjected to requests that are not acknowledged, until the server is no longer able to respond to any requests in a timely manner.--[[User:Omei Turnbull|Omei Turnbull]] 12:59, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::Thats what I was thinking. -- [[User:Strife Onizuka|Strife Onizuka]] 15:27, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:::: Though there are certain things you could do to stave off DoS attacks like refusing to serve more than N connections at a time and refusing to even open a tcp connection to any future ones, I agree that without further consideration it&#039;s probably not a good idea to do chttp between hosts that don&#039;t trust each other.  [[User:Which Linden|Which Linden]] 21:12, 3 October 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::This could be mitigated by adding a header field in the client message saying whether this is an initial or a follow-up request.  The server would not be required to check initial requests against its history of open requests.  Follow-up requests, which would require a lookup against the open requests, could be done at reduced priority, so that they don&#039;t interfere with normal traffic.--[[User:Omei Turnbull|Omei Turnbull]] 16:43, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::: Wow, how did I not see this earlier?  I think that the problem with this idea is that the client doesn&#039;t, in general, know whether it&#039;s making an initial or a follow up request.  If it hasn&#039;t received a response from the server, it doesn&#039;t know whether the server received the message and didn&#039;t respond, or if the message never made it to the server in the first place (or was incomplete, as would happen if the network died mid-send).  [[User:Which Linden|Which Linden]] 21:12, 3 October 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Thoughts ==&lt;br /&gt;
For a simple setup X-Message-URL could be the original request URL. The DELETE command should send the same X-Message-ID as the orig request to better facilitate this. This would have the added benefit that a client could possibly cancel a request by sending a DELETE before getting a response.&lt;br /&gt;
This doesn&#039;t have to be all that complicated to implement. Once a request comes in, check to see if there is a DB entry for it, if it does not exist in the DB, execute the command and write the body to file and return the body. If it does exist in the DB already, check the status of the request, if there is a body, return it and wait for the timeout or DELETE command before removing the DB entry. -- [[User:Strife Onizuka|Strife Onizuka]] 15:34, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
== Cleanup ==&lt;br /&gt;
&lt;br /&gt;
Limiting the number of concurrent requests per client is one way of reducing DOS risk but if a client crashes and reconnects then it will need some way of finding out what requests need to be closed. There should probably be some interface the client can query the server to find out what requests it has open. The response to such a query would give URLs to close those requests but they should not be able to return those request&#039;s response bodies as that could be a security breach. Additionally those requests returned should be tagged with the session that created them and the status of that session (so multiple sessions can use the same authorization information concurrently). -- [[User:Strife Onizuka|Strife Onizuka]] 16:24, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
:This is a really interesting point.  We&#039;ve given very little thought to communication with untrusted and unreliable clients.  Right now, we are assuming that the client is a reliable service itself -- chttp is essentially a peer protocol between durable hosts.  In particular, we want to assume delivery, which means that all the application logic doesn&#039;t have to contain a lot of failure cases (always a bugbear to write and test). The application just assumes that the message will eventually make it, despite temporary failures on both sending and receiving hosts.  With those assumptions, it&#039;s reasonable to say that the client doesn&#039;t need to query the server to find out what requests it has open.  It&#039;s not clear if the semantics even mean anything if the client is untrusted or unreliable.  [[User:Which Linden|Which Linden]] 22:01, 11 July 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::Perhaps there needs to be a way of identifing trusted hosts? Perhaps using HTTP authentication on servers that require identity? and if they can be identified, don&#039;t apply a limit to concurrent requests or at least increase the limit? Though this would surely make https as the perfered protocol in such a case, so authentication information is more secure. -- [[User:Nik Woodget|Nik Woodget]] 10:20, 19 September 2007&lt;br /&gt;
&lt;br /&gt;
::: Could use client certificates, too.  I think specifying an authentication method is outside the scope of certified http, though.  [[User:Which Linden|Which Linden]] 21:59, 3 October 2007 (PDT)&lt;br /&gt;
&lt;br /&gt;
::: As much as possible, things like authentication, should follow existing http style practice. I&#039;d like to see it compose with the related specs. This seems like an overall good principle [[User: Zha Ewry|Zha Ewry]] 12:40 3 October 2007&lt;br /&gt;
&lt;br /&gt;
== Status Codes ==&lt;br /&gt;
&lt;br /&gt;
I suggest should adjust interpretation of a few of the status codes.&lt;br /&gt;
; 304 Not Modified : I believe we should add a requirement that no cHTTP enabled server will return 304 to any request which include x-message-id. In order to maintain idempotence, we should typically return 200, but at least we should return 200 &amp;lt;= status &amp;lt; 300.&lt;br /&gt;
; 203 Non-Authoritative Information : I think we should consider this a success because the use case where this makes sense is if the server has a secondary persistent store which it considers good enough for this particular transaction. It also makes me nervous to think of anything in 2xx other than 202 as a retry.&lt;br /&gt;
; 406 Not Acceptable : Since the persisted client request theoretically includes the Accept header, there is no way that further calls will ever return anything other than 406. So shouldn&#039;t we fail sooner?&lt;br /&gt;
; 411 Length Required : A cHTTP dialogue requires Content-Length for every non-zero length message so this sound like a permanent failure to me.&lt;br /&gt;
&lt;br /&gt;
[[User:Phoenix Linden|Phoenix Linden]] 22:28, 1 November 2007 (PDT)&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Compiling_Issues_with_Vista/MSVS2008&amp;diff=35151</id>
		<title>Compiling Issues with Vista/MSVS2008</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Compiling_Issues_with_Vista/MSVS2008&amp;diff=35151"/>
		<updated>2007-10-11T15:54:24Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: Compiling Issues with Vista/MSVS2008 moved to Compiling Issues with Vista and MSVS2008&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Compiling Issues with Vista and MSVS2008]]&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=User:Stefano_CiscoSystems/Compiling_Issues_with_Vista_and_MSVS2008&amp;diff=35150</id>
		<title>User:Stefano CiscoSystems/Compiling Issues with Vista and MSVS2008</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=User:Stefano_CiscoSystems/Compiling_Issues_with_Vista_and_MSVS2008&amp;diff=35150"/>
		<updated>2007-10-11T15:54:24Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: Compiling Issues with Vista/MSVS2008 moved to Compiling Issues with Vista and MSVS2008&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== could not deduce template argument from &#039;LLMessageThrottleEntry&#039; in llmessagethrottle.cpp ==&lt;br /&gt;
* [VS9PATH]\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::deque&amp;lt;_Ty,_Alloc&amp;gt; &amp;amp;,const std::deque&amp;lt;_Ty,_Alloc&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const std::deque&amp;lt;_Ty,_Alloc&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
* [VS9PATH]\vc\include\deque(1341) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
* [VS9PATH]\vc\include\algorithm(435) : see reference to function template instantiation &#039;_FwdIt1 std::_Search_n&amp;lt;_FwdIt1,_Diff2,_Ty,bool(__cdecl *)(LLMessageThrottleEntry,LLMessageThrottleEntry)&amp;gt;(_FwdIt1,_FwdIt1,_Diff2,const _Ty &amp;amp;,_Pr,std::random_access_iterator_tag)&#039; being compiled&lt;br /&gt;
&lt;br /&gt;
The first error is related to the search_n for the LLMessageThrottleEntry class on line 113 of \indra\llmessage\llmessagethrottle.cpp.&lt;br /&gt;
&lt;br /&gt;
The error happens in [yourpath]\Visual Studio 9.0\vc\include\algorithm, on line 406 (excerpt follows)&lt;br /&gt;
&lt;br /&gt;
  template&amp;lt;class _FwdIt1,&lt;br /&gt;
 	class _Diff2,&lt;br /&gt;
 	class _Ty,&lt;br /&gt;
 	class _Pr&amp;gt; inline&lt;br /&gt;
 	_FwdIt1 _Search_n(_FwdIt1 _First1, _FwdIt1 _Last1,&lt;br /&gt;
 		_Diff2 _Count, const _Ty&amp;amp; _Val, _Pr _Pred, random_access_iterator_tag)&lt;br /&gt;
 	{	// find first _Count * _Val satisfying _Pred, random-access iterators&lt;br /&gt;
 	_DEBUG_RANGE(_First1, _Last1);&lt;br /&gt;
 	_DEBUG_POINTER(_Pred);&lt;br /&gt;
  &lt;br /&gt;
 	if (_Count &amp;lt;= 0)&lt;br /&gt;
 		return (_First1);&lt;br /&gt;
  &lt;br /&gt;
  	_FwdIt1 _Oldfirst1 = _First1;&lt;br /&gt;
 	for (; _Count &amp;lt;= _Last1 - _Oldfirst1; )&lt;br /&gt;
 		{	// enough room, look for a match &lt;br /&gt;
 		if (_Pred(*_First1, _Val))&lt;br /&gt;
 			{	// found part of possible match, check it out&lt;br /&gt;
 			_Diff2 _Count1 = _Count;&lt;br /&gt;
 			_FwdIt1 _Mid1  = _First1;&lt;br /&gt;
  &lt;br /&gt;
 406:			for (; _Oldfirst1 != _First1 &amp;amp;&amp;amp; _First1[-1] == _Val; --_First1)&lt;br /&gt;
 				--_Count1;	// back up over any skipped prefix&lt;br /&gt;
  &lt;br /&gt;
 			if (_Count1 &amp;lt;= _Last1 - _Mid1)&lt;br /&gt;
 				for (; ; )	// enough left, test suffix&lt;br /&gt;
 					if (--_Count1 == 0)&lt;br /&gt;
 						return (_First1);	// found rest of match, report it&lt;br /&gt;
 					else if (!_Pred(*++_Mid1, _Val))&lt;br /&gt;
 						break;	// short match not at end&lt;br /&gt;
  &lt;br /&gt;
 			_Oldfirst1 = ++_Mid1;	// failed match, take small jump&lt;br /&gt;
 			_First1 = _Oldfirst1;&lt;br /&gt;
 			}&lt;br /&gt;
 		else&lt;br /&gt;
 			{	// no match, take big jump and back up as needed&lt;br /&gt;
 			_Oldfirst1 = _First1 + 1;&lt;br /&gt;
 			_First1 += _Count;&lt;br /&gt;
 			}&lt;br /&gt;
 		}&lt;br /&gt;
 	return (_Last1);&lt;br /&gt;
 	}&lt;br /&gt;
 &lt;br /&gt;
So the problem seems to be the operator == in the equality:&lt;br /&gt;
 _First1[-1] == _Val; &lt;br /&gt;
coming from the search_n operation.&lt;br /&gt;
&lt;br /&gt;
They both evaluate to a &lt;br /&gt;
 const std::deque&amp;lt;_Ty,_Alloc&amp;gt; &amp;amp;&lt;br /&gt;
which types are ambiguous for the compiler.&lt;br /&gt;
&lt;br /&gt;
Here is the exact copy of the full compilation error:&lt;br /&gt;
&lt;br /&gt;
 1&amp;gt;------ Build started: Project: llmessage, Configuration: Debug Win32 ------&lt;br /&gt;
 1&amp;gt;Compiling...&lt;br /&gt;
 1&amp;gt;llmessagethrottle.cpp&lt;br /&gt;
 1&amp;gt;c:\sources\secondlife\lindenlabclient\indra\llmessage\llmessagethrottle.cpp(134) : warning C4189: &#039;message_list&#039; : local variable is initialized but not referenced&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::deque&amp;lt;_Ty,_Alloc&amp;gt; &amp;amp;,const std::deque&amp;lt;_Ty,_Alloc&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const std::deque&amp;lt;_Ty,_Alloc&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\deque(1341) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(435) : see reference to function template instantiation &#039;_FwdIt1 std::_Search_n&amp;lt;_FwdIt1,_Diff2,_Ty,bool(__cdecl *)(LLMessageThrottleEntry,LLMessageThrottleEntry)&amp;gt;(_FwdIt1,_FwdIt1,_Diff2,const _Ty &amp;amp;,_Pr,std::random_access_iterator_tag)&#039; being compiled&lt;br /&gt;
 1&amp;gt;        with&lt;br /&gt;
 1&amp;gt;        [&lt;br /&gt;
 1&amp;gt;            _FwdIt1=LLMessageThrottle::message_list_iterator_t,&lt;br /&gt;
 1&amp;gt;            _Diff2=int,&lt;br /&gt;
 1&amp;gt;            _Ty=LLMessageThrottleEntry,&lt;br /&gt;
 1&amp;gt;            _Pr=bool (__cdecl *)(LLMessageThrottleEntry,LLMessageThrottleEntry)&lt;br /&gt;
 1&amp;gt;        ]&lt;br /&gt;
 1&amp;gt;        c:\sources\secondlife\lindenlabclient\indra\llmessage\llmessagethrottle.cpp(117) : see reference to function template instantiation &#039;_FwdIt1 std::search_n&amp;lt;LLMessageThrottle::message_list_iterator_t,int,LLMessageThrottleEntry,bool(__cdecl *)(LLMessageThrottleEntry,LLMessageThrottleEntry)&amp;gt;(_FwdIt1,_FwdIt1,_Diff2,const _Ty &amp;amp;,_Pr)&#039; being compiled&lt;br /&gt;
 1&amp;gt;        with&lt;br /&gt;
 1&amp;gt;        [&lt;br /&gt;
 1&amp;gt;            _FwdIt1=LLMessageThrottle::message_list_iterator_t,&lt;br /&gt;
 1&amp;gt;            _Diff2=int,&lt;br /&gt;
 1&amp;gt;            _Ty=LLMessageThrottleEntry,&lt;br /&gt;
 1&amp;gt;            _Pr=bool (__cdecl *)(LLMessageThrottleEntry,LLMessageThrottleEntry)&lt;br /&gt;
 1&amp;gt;        ]&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::list&amp;lt;_Ty,_Ax&amp;gt; &amp;amp;,const std::list&amp;lt;_Ty,_Ax&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const std::list&amp;lt;_Ty,_Ax&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\list(1299) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::_Tree&amp;lt;_Traits&amp;gt; &amp;amp;,const std::_Tree&amp;lt;_Traits&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const std::_Tree&amp;lt;_Traits&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\xtree(1459) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::basic_string&amp;lt;_Elem,_Traits,_Alloc&amp;gt; &amp;amp;,const _Elem *)&#039; : could not deduce template argument for &#039;const std::basic_string&amp;lt;_Elem,_Traits,_Alloc&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\string(90) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const _Elem *,const std::basic_string&amp;lt;_Elem,_Traits,_Alloc&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const _Elem *&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\string(80) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::basic_string&amp;lt;_Elem,_Traits,_Alloc&amp;gt; &amp;amp;,const std::basic_string&amp;lt;_Elem,_Traits,_Alloc&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const std::basic_string&amp;lt;_Elem,_Traits,_Alloc&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\string(70) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::vector&amp;lt;_Ty,_Alloc&amp;gt; &amp;amp;,const std::vector&amp;lt;_Ty,_Alloc&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const std::vector&amp;lt;_Ty,_Alloc&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\vector(1309) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::istream_iterator&amp;lt;_Ty,_Elem,_Traits,_Diff&amp;gt; &amp;amp;,const std::istream_iterator&amp;lt;_Ty,_Elem,_Traits,_Diff&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const std::istream_iterator&amp;lt;_Ty,_Elem,_Traits,_Diff&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\iterator(266) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::istreambuf_iterator&amp;lt;_Elem,_Traits&amp;gt; &amp;amp;,const std::istreambuf_iterator&amp;lt;_Elem,_Traits&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const std::istreambuf_iterator&amp;lt;_Elem,_Traits&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\streambuf(548) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::allocator&amp;lt;_Ty&amp;gt; &amp;amp;,const std::allocator&amp;lt;_Other&amp;gt; &amp;amp;) throw()&#039; : could not deduce template argument for &#039;const std::allocator&amp;lt;_Ty&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\xmemory(173) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::reverse_iterator&amp;lt;_RanIt&amp;gt; &amp;amp;,const std::reverse_iterator&amp;lt;_RanIt2&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const std::reverse_iterator&amp;lt;_RanIt&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\xutility(2193) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::_Revranit&amp;lt;_RanIt,_Base&amp;gt; &amp;amp;,const std::_Revranit&amp;lt;_RanIt2,_Base2&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const std::_Revranit&amp;lt;_RanIt,_Base&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\xutility(2007) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2784: &#039;bool std::operator ==(const std::pair&amp;lt;_Ty1,_Ty2&amp;gt; &amp;amp;,const std::pair&amp;lt;_Ty1,_Ty2&amp;gt; &amp;amp;)&#039; : could not deduce template argument for &#039;const std::pair&amp;lt;_Ty1,_Ty2&amp;gt; &amp;amp;&#039; from &#039;LLMessageThrottleEntry&#039;&lt;br /&gt;
 1&amp;gt;        c:\program files\development\microsoft visual studio 9.0\vc\include\utility(68) : see declaration of &#039;std::operator ==&#039;&lt;br /&gt;
 1&amp;gt;c:\program files\development\microsoft visual studio 9.0\vc\include\algorithm(406) : error C2676: binary &#039;==&#039; : &#039;LLMessageThrottleEntry&#039; does not define this operator or a conversion to a type acceptable to the predefined operator&lt;br /&gt;
 1&amp;gt;Build log was saved at &amp;quot;file://c:\Sources\SecondLife\LindenLabClient\indra\llmessage\Debug\BuildLog.htm&amp;quot;&lt;br /&gt;
 1&amp;gt;llmessage - 14 error(s), 1 warning(s)&lt;br /&gt;
 ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========&lt;br /&gt;
&lt;br /&gt;
And this is the content of the file llmessagethrottle.cpp that i am using:&lt;br /&gt;
&lt;br /&gt;
 /** &lt;br /&gt;
  * @file llmessagethrottle.cpp&lt;br /&gt;
  * @brief LLMessageThrottle class used for throttling messages.&lt;br /&gt;
  *&lt;br /&gt;
  * Copyright (c) 2004-2007, Linden Research, Inc.&lt;br /&gt;
  * &lt;br /&gt;
  * Second Life Viewer Source Code&lt;br /&gt;
  * The source code in this file (&amp;quot;Source Code&amp;quot;) is provided by Linden Lab&lt;br /&gt;
  * to you under the terms of the GNU General Public License, version 2.0&lt;br /&gt;
  * (&amp;quot;GPL&amp;quot;), unless you have obtained a separate licensing agreement&lt;br /&gt;
  * (&amp;quot;Other License&amp;quot;), formally executed by you and Linden Lab.  Terms of&lt;br /&gt;
  * the GPL can be found in doc/GPL-license.txt in this distribution, or&lt;br /&gt;
  * online at http://secondlife.com/developers/opensource/gplv2&lt;br /&gt;
  * &lt;br /&gt;
  * There are special exceptions to the terms and conditions of the GPL as&lt;br /&gt;
  * it is applied to this Source Code. View the full text of the exception&lt;br /&gt;
  * in the file doc/FLOSS-exception.txt in this software distribution, or&lt;br /&gt;
  * online at http://secondlife.com/developers/opensource/flossexception&lt;br /&gt;
  * &lt;br /&gt;
  * By copying, modifying or distributing this software, you acknowledge&lt;br /&gt;
  * that you have read and understood your obligations described above,&lt;br /&gt;
  * and agree to abide by those obligations.&lt;br /&gt;
  * &lt;br /&gt;
  * ALL LINDEN LAB SOURCE CODE IS PROVIDED &amp;quot;AS IS.&amp;quot; LINDEN LAB MAKES NO&lt;br /&gt;
  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,&lt;br /&gt;
  * COMPLETENESS OR PERFORMANCE.&lt;br /&gt;
  */&lt;br /&gt;
  &lt;br /&gt;
 #include &amp;quot;linden_common.h&amp;quot; &lt;br /&gt;
 #include &amp;quot;llhash.h&amp;quot;&lt;br /&gt;
  &lt;br /&gt;
 #include &amp;quot;llmessagethrottle.h&amp;quot;&lt;br /&gt;
 #include &amp;quot;llframetimer.h&amp;quot;&lt;br /&gt;
   &lt;br /&gt;
 // This is used for the stl search_n function.&lt;br /&gt;
  bool eq_message_throttle_entry(LLMessageThrottleEntry a, LLMessageThrottleEntry b)&lt;br /&gt;
  		{ return a.getHash() == b.getHash(); }&lt;br /&gt;
  &lt;br /&gt;
 const U64 SEC_TO_USEC = 1000000;&lt;br /&gt;
 		&lt;br /&gt;
 // How long (in microseconds) each type of message stays in its throttle list.&lt;br /&gt;
 const U64 MAX_MESSAGE_AGE[MTC_EOF] =&lt;br /&gt;
 {&lt;br /&gt;
 	10 * SEC_TO_USEC,	// MTC_VIEWER_ALERT&lt;br /&gt;
 	10 * SEC_TO_USEC	// MTC_AGENT_ALERT&lt;br /&gt;
 };&lt;br /&gt;
  &lt;br /&gt;
 LLMessageThrottle::LLMessageThrottle()&lt;br /&gt;
 {&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 LLMessageThrottle::~LLMessageThrottle()&lt;br /&gt;
 {&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 void LLMessageThrottle::pruneEntries()&lt;br /&gt;
 {&lt;br /&gt;
 	// Go through each message category, and prune entries older than max age.&lt;br /&gt;
 	S32 cat;&lt;br /&gt;
 	for (cat = 0; cat &amp;lt; MTC_EOF; cat++)&lt;br /&gt;
 	{&lt;br /&gt;
 		message_list_t* message_list = &amp;amp;(mMessageList[cat]);&lt;br /&gt;
  &lt;br /&gt;
 		// Use a reverse iterator, since entries on the back will be the oldest.&lt;br /&gt;
 		message_list_reverse_iterator_t r_iterator 	= message_list-&amp;gt;rbegin();&lt;br /&gt;
 		message_list_reverse_iterator_t r_last 		= message_list-&amp;gt;rend();&lt;br /&gt;
  &lt;br /&gt;
 		// Look for the first entry younger than the maximum age.&lt;br /&gt;
 		F32 max_age = (F32)MAX_MESSAGE_AGE[cat]; &lt;br /&gt;
 		BOOL found = FALSE;&lt;br /&gt;
 		while (r_iterator != r_last &amp;amp;&amp;amp; !found)&lt;br /&gt;
 		{&lt;br /&gt;
 			if ( LLFrameTimer::getTotalTime() - (*r_iterator).getEntryTime() &amp;lt; max_age )&lt;br /&gt;
 			{&lt;br /&gt;
 				// We found a young enough entry.&lt;br /&gt;
 				found = TRUE;&lt;br /&gt;
  &lt;br /&gt;
 				// Did we find at least one entry to remove?&lt;br /&gt;
 				if (r_iterator != message_list-&amp;gt;rbegin())&lt;br /&gt;
 				{&lt;br /&gt;
 					// Yes, remove it.&lt;br /&gt;
 					message_list-&amp;gt;erase(r_iterator.base(), message_list-&amp;gt;end());&lt;br /&gt;
 				}&lt;br /&gt;
 			}&lt;br /&gt;
 			else&lt;br /&gt;
 			{&lt;br /&gt;
 				r_iterator++;&lt;br /&gt;
 			}&lt;br /&gt;
 		}&lt;br /&gt;
  &lt;br /&gt;
 		// If we didn&#039;t find any entries young enough to keep, remove them all.&lt;br /&gt;
 		if (!found)&lt;br /&gt;
 		{&lt;br /&gt;
 			message_list-&amp;gt;clear();&lt;br /&gt;
 		}&lt;br /&gt;
 	}&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 BOOL LLMessageThrottle::addViewerAlert(const LLUUID&amp;amp; to, const char* mesg)&lt;br /&gt;
 {&lt;br /&gt;
 	message_list_t* message_list = &amp;amp;(mMessageList[MTC_VIEWER_ALERT]);&lt;br /&gt;
  &lt;br /&gt;
 	// Concatenate from,to,mesg into one string.&lt;br /&gt;
 	std::ostringstream full_mesg;&lt;br /&gt;
 	full_mesg &amp;lt;&amp;lt; to &amp;lt;&amp;lt; mesg;&lt;br /&gt;
  &lt;br /&gt;
 	// Create an entry for this message.&lt;br /&gt;
 	size_t hash = llhash&amp;lt;const char*&amp;gt; (full_mesg.str().c_str());&lt;br /&gt;
 	LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime());&lt;br /&gt;
  &lt;br /&gt;
 	// Check if this message is already in the list.&lt;br /&gt;
 	/*&lt;br /&gt;
         * Stefano: i did try using this but did not help: &lt;br /&gt;
 	&amp;lt;message_list_iterator_t,int,LLMessageThrottleEntry,bool (__cdecl *)(LLMessageThrottleEntry,LLMessageThrottleEntry)&amp;gt;&lt;br /&gt;
 	*/&lt;br /&gt;
 	message_list_iterator_t found = std::search_n(message_list-&amp;gt;begin(), message_list-&amp;gt;end(), 1, entry, eq_message_throttle_entry);&lt;br /&gt;
  &lt;br /&gt;
 	if (found == message_list-&amp;gt;end())&lt;br /&gt;
 	{&lt;br /&gt;
 		// This message was not found.  Add it to the list.&lt;br /&gt;
 		message_list-&amp;gt;push_front(entry);&lt;br /&gt;
 		return TRUE;&lt;br /&gt;
 	}&lt;br /&gt;
 	else&lt;br /&gt;
 	{&lt;br /&gt;
 		// This message was already in the list.&lt;br /&gt;
 		return FALSE;&lt;br /&gt;
 	}&lt;br /&gt;
 }&lt;br /&gt;
   &lt;br /&gt;
 BOOL LLMessageThrottle::addAgentAlert(const LLUUID&amp;amp; agent, const LLUUID&amp;amp; task, const char* mesg)&lt;br /&gt;
 {&lt;br /&gt;
 	message_list_t* message_list = &amp;amp;(mMessageList[MTC_AGENT_ALERT]);&lt;br /&gt;
  &lt;br /&gt;
 	// Concatenate from,to,mesg into one string.&lt;br /&gt;
 	std::ostringstream full_mesg;&lt;br /&gt;
 	full_mesg &amp;lt;&amp;lt; agent &amp;lt;&amp;lt; task &amp;lt;&amp;lt; mesg;&lt;br /&gt;
  &lt;br /&gt;
 	// Create an entry for this message.&lt;br /&gt;
 	size_t hash = llhash&amp;lt;const char*&amp;gt; (full_mesg.str().c_str());&lt;br /&gt;
 	LLMessageThrottleEntry entry(hash, LLFrameTimer::getTotalTime());&lt;br /&gt;
  &lt;br /&gt;
 	// Check if this message is already in the list.&lt;br /&gt;
 /* stefano i commented the following so to get one only error while debugging */&lt;br /&gt;
 /*	message_list_iterator_t found = std::search_n(message_list-&amp;gt;begin(), message_list-&amp;gt;end(), &lt;br /&gt;
                                                      1, entry, eq_message_throttle_entry);    	&lt;br /&gt;
  &lt;br /&gt;
 	if (found == message_list-&amp;gt;end())&lt;br /&gt;
 	{&lt;br /&gt;
 		// This message was not found.  Add it to the list.&lt;br /&gt;
 		message_list-&amp;gt;push_front(entry);&lt;br /&gt;
 		return TRUE;&lt;br /&gt;
 	}&lt;br /&gt;
 	else&lt;br /&gt;
 	{&lt;br /&gt;
 		// This message was already in the list.&lt;br /&gt;
 		return FALSE;&lt;br /&gt;
 	}&lt;br /&gt;
 	*/&lt;br /&gt;
  &lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Recursive_URL_Substitution_Syntax&amp;diff=27110</id>
		<title>Recursive URL Substitution Syntax</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Recursive_URL_Substitution_Syntax&amp;diff=27110"/>
		<updated>2007-08-03T18:24:56Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* Strings */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Like any substitution syntax, using untrusted formatted strings or untrusted sources of data can lead to exploits. Be careful when designing the usage so that no tainted input winds up in the context.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Syntax =&lt;br /&gt;
The syntax is based on placing curly braces inside an URL to indicate that the curly brace and everything inside should be replaced with a substitution. Each type of substitution will have it&#039;s own rules but every time you see { and } then all contents inside those braces are to be replaced.&lt;br /&gt;
&lt;br /&gt;
== Strings ==&lt;br /&gt;
String substitution uses an open curly brace &#039;{&#039; followed by a dollar symbol &#039;$&#039; followed by the name of the substitution and a closing curly brace &#039;}&#039;. The name is used as a key into a map whose value will be replaced into the original format string. The key must only contain alphanumeric characters and &#039;+&#039;, &#039;-&#039;, &#039;_&#039;, and spaces.&lt;br /&gt;
&lt;br /&gt;
Values which appear in the map but not referenced in the format string are ignored.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ String Substitution Examples&lt;br /&gt;
! Format !! Map Contents !! Result&lt;br /&gt;
|-&lt;br /&gt;
| {$bucket}.agent.lindenlab.com&lt;br /&gt;
| &#039;bucket&#039;:&#039;a&#039;&lt;br /&gt;
| a.agent.lindenlab.com&lt;br /&gt;
|-&lt;br /&gt;
| agent/{$agent-id}/inventory/item/{$item-id}&lt;br /&gt;
| &#039;agent-id&#039;:foo, &#039;item-id&#039;:bar&lt;br /&gt;
| agent/foo/inventory/item/bar&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Values which are lists/tuples will have their elements urlquoted and joined with &#039;/&#039;.  I.e. they are assumed to be exploded paths.  E.g.:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Format !! Map Contents !! Result&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;foo/{$stuff}/baz&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;&#039;stuff&#039;:[&#039;one&#039;,&#039;two&#039;,&#039;three&#039;]&amp;lt;/code&amp;gt;&lt;br /&gt;
| &amp;lt;code&amp;gt;foo/one/two/three/baz&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Query Strings ==&lt;br /&gt;
Query strings are a specialized url syntax for representing the contents of a map as an ampersand delimited url query string including the leading &#039;?&#039;. Query string use an open curly brace &#039;{&#039; followed by a percent symbol &#039;%&#039; followed by the name of a dictionary in the replacement context followed by a closing curly brace &#039;}&#039;.&lt;br /&gt;
&lt;br /&gt;
Unlike string substitution, if the named value is not a key in the map contents, the russ directive will be stripped.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Query String Substitution Examples&lt;br /&gt;
! Format !! Map Contents !! Result&lt;br /&gt;
|-&lt;br /&gt;
| /sql/{$query}{%params}&lt;br /&gt;
| { &#039;query&#039;:&#039;get-agent-name-by-id&#039;, &#039;params&#039;:{&#039;agent_id&#039;:123}}&lt;br /&gt;
| /sql/get-agent-name-by-id?agent_id=123&lt;br /&gt;
|-&lt;br /&gt;
| /proc/{$proc}{%params}&lt;br /&gt;
| { &#039;proc&#039;:&#039;messages/dir/DirFindPeople&#039;, &#039;params&#039;:{&#039;estate&#039;:1, &#039;query&#039;:&#039;designer clothing&#039;}}&lt;br /&gt;
| /proc/messages/dir/DirFindPeople?estate=1&amp;amp;query=designer+clothing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
Function substitution uses an open curly brace &#039;{&#039; followed by a bang symbol &#039;!&#039; followed by the name of the substitution function and a closing curly brace &#039;}&#039;. The name is a function that is available to the substitution engine, and may be implementation specific. The function is prototyped as accepting a map context and returning a string.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;b&amp;gt;{!region-host-port}&amp;lt;/b&amp;gt; could be a function which takes a map which is assumed to contain a key &amp;lt;code&amp;gt;&#039;region-id&#039;&amp;lt;/code&amp;gt;. The function will perform a service lookup for region presence with the region-id in the service builder, and then parse the return document for the region host and port.&lt;br /&gt;
&lt;br /&gt;
== REST Requests ==&lt;br /&gt;
For REST Request substitution, the embedded URL is fetched, parsed for a single [[LLSD]] document which is embedded inside the curly braces. &lt;br /&gt;
&lt;br /&gt;
The simple syntax is an opening curly brace &#039;{&#039;, followed by the URL, and terminated with a closing curly brace &#039;}&#039;. The document at the url is parsed and treated as a string. Containers, the undefined element, and non-parseable documents are considered errors.&lt;br /&gt;
&lt;br /&gt;
For http request, no instructions to the protocol means to perform a normal GET.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Rest Request Substitution Examples&lt;br /&gt;
! Format !! Results&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;{http://gridtool.agni.lindenlab.com/agents/online-now}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| 58582&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;{http://blondie.lindenlab.com/lookup/agentname/phoenix/linden||agent-id}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| 3c115e51-04f4-523c-9fa6-98aff1034730&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Supported protocols: http, https &lt;br /&gt;
&lt;br /&gt;
We should probably support file.&lt;br /&gt;
&lt;br /&gt;
== Recursive Substitution ==&lt;br /&gt;
In theory, this grammar can be used recursively, though only python currently supports this feature.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Formating Examples&lt;br /&gt;
! Format&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;{http://sim1028.{$grid}.{$domain}/agent/{$agent-id}/location}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| {{$node}{$domain}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Syntax Specification =&lt;br /&gt;
The full syntax is an opening curly brace &#039;{&#039;, followed by the URL, followed by a vline &#039;|&#039;, followed by protocol specific instructions, followed by a &#039;vline&#039;, followed by a path to follow through the document to the element which will be treated as a string. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
russ-statement : open-russ substitution close-russ&lt;br /&gt;
open-russ: &#039;{&#039;&lt;br /&gt;
close-russ: &#039;}&#039;&lt;br /&gt;
substituion: string-substitution| query-string-substitution | url-substitution | function-substitution&lt;br /&gt;
string-substition: &#039;$&#039; llsd-key&lt;br /&gt;
query-string-substition: &#039;%&#039; llsd-key&lt;br /&gt;
function-substitution: &#039;!&#039; function-name&lt;br /&gt;
function-name: llsd-key&lt;br /&gt;
url-substitution: url [ vline [ url-parameters ] vline llsd-path]&lt;br /&gt;
url: protocol &#039;:&#039; (normal url authority &amp;amp; host &amp;amp; path &amp;amp; parameters &amp;amp; opaque parts)&lt;br /&gt;
protocol: &#039;http&#039; | &#039;https&#039;&lt;br /&gt;
vline: &#039;|&#039;&lt;br /&gt;
url-parameters: verb [ body ]&lt;br /&gt;
verb: &#039;GET&#039; | &#039;PUT&#039; | &#039;POST&#039; | &#039;DELETE&#039;&lt;br /&gt;
body: ???&lt;br /&gt;
llsd-path: segment * [ &amp;quot;/&amp;quot; segment ]&lt;br /&gt;
segment: llsd-key&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Please note that the following elements in the syntax rules are not well defined:&lt;br /&gt;
* llsd-key&lt;br /&gt;
* body&lt;br /&gt;
* function-name&lt;br /&gt;
&lt;br /&gt;
= Implementations =&lt;br /&gt;
== python ==&lt;br /&gt;
Our indra python libs have a russ implementation in russ.py which supports:&lt;br /&gt;
* string substitution&lt;br /&gt;
* query string substitution&lt;br /&gt;
* url substitution&lt;br /&gt;
* recursive substitution&lt;br /&gt;
&lt;br /&gt;
== c++ ==&lt;br /&gt;
In indra/llmessage libs has a russ implementation inside of the LLServiceBuilder class which supports:&lt;br /&gt;
* string substitution&lt;br /&gt;
* url substitution&lt;br /&gt;
&lt;br /&gt;
== perl ==&lt;br /&gt;
In &amp;lt;code&amp;gt;Indra::WebServices&amp;lt;/code&amp;gt;, you can call &amp;lt;code&amp;gt;buildService($service_name)&amp;lt;/code&amp;gt; to make a client to that service. The current implementation supports:&lt;br /&gt;
* string substitution&lt;br /&gt;
* query string substitution&lt;br /&gt;
* recursive substitution&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Recursive_URL_Substitution_Syntax&amp;diff=27109</id>
		<title>Recursive URL Substitution Syntax</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Recursive_URL_Substitution_Syntax&amp;diff=27109"/>
		<updated>2007-08-03T18:24:23Z</updated>

		<summary type="html">&lt;p&gt;Phoenix Linden: /* c++ */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Like any substitution syntax, using untrusted formatted strings or untrusted sources of data can lead to exploits. Be careful when designing the usage so that no tainted input winds up in the context.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Syntax =&lt;br /&gt;
The syntax is based on placing curly braces inside an URL to indicate that the curly brace and everything inside should be replaced with a substitution. Each type of substitution will have it&#039;s own rules but every time you see { and } then all contents inside those braces are to be replaced.&lt;br /&gt;
&lt;br /&gt;
== Strings ==&lt;br /&gt;
String substitution uses an open curly brace &#039;{&#039; followed by a dollar symbol &#039;$&#039; followed by the name of the substitution and a closing curly brace &#039;}&#039;. The name is used as a key into a map whose value will be replaced into the original format string. The key must only contain alphanumeric characters and &#039;+&#039;, &#039;-&#039;, &#039;_&#039;, and spaces.&lt;br /&gt;
&lt;br /&gt;
Values which appear in the map but not referenced in the format string are ignored.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ String Substitution Examples&lt;br /&gt;
! Format !! Map Contents !! Result&lt;br /&gt;
|-&lt;br /&gt;
| {$bucket}.agent.lindenlab.com&lt;br /&gt;
| &#039;bucket&#039;:&#039;a&#039;&lt;br /&gt;
| a.agent.lindenlab.com&lt;br /&gt;
|-&lt;br /&gt;
| agent/{$agent-id}/inventory/item/{$item-id}&lt;br /&gt;
| &#039;agent-id&#039;:foo, &#039;item-id&#039;:bar&lt;br /&gt;
| agent/foo/inventory/item/bar&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Query Strings ==&lt;br /&gt;
Query strings are a specialized url syntax for representing the contents of a map as an ampersand delimited url query string including the leading &#039;?&#039;. Query string use an open curly brace &#039;{&#039; followed by a percent symbol &#039;%&#039; followed by the name of a dictionary in the replacement context followed by a closing curly brace &#039;}&#039;.&lt;br /&gt;
&lt;br /&gt;
Unlike string substitution, if the named value is not a key in the map contents, the russ directive will be stripped.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Query String Substitution Examples&lt;br /&gt;
! Format !! Map Contents !! Result&lt;br /&gt;
|-&lt;br /&gt;
| /sql/{$query}{%params}&lt;br /&gt;
| { &#039;query&#039;:&#039;get-agent-name-by-id&#039;, &#039;params&#039;:{&#039;agent_id&#039;:123}}&lt;br /&gt;
| /sql/get-agent-name-by-id?agent_id=123&lt;br /&gt;
|-&lt;br /&gt;
| /proc/{$proc}{%params}&lt;br /&gt;
| { &#039;proc&#039;:&#039;messages/dir/DirFindPeople&#039;, &#039;params&#039;:{&#039;estate&#039;:1, &#039;query&#039;:&#039;designer clothing&#039;}}&lt;br /&gt;
| /proc/messages/dir/DirFindPeople?estate=1&amp;amp;query=designer+clothing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Functions ==&lt;br /&gt;
Function substitution uses an open curly brace &#039;{&#039; followed by a bang symbol &#039;!&#039; followed by the name of the substitution function and a closing curly brace &#039;}&#039;. The name is a function that is available to the substitution engine, and may be implementation specific. The function is prototyped as accepting a map context and returning a string.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;b&amp;gt;{!region-host-port}&amp;lt;/b&amp;gt; could be a function which takes a map which is assumed to contain a key &amp;lt;code&amp;gt;&#039;region-id&#039;&amp;lt;/code&amp;gt;. The function will perform a service lookup for region presence with the region-id in the service builder, and then parse the return document for the region host and port.&lt;br /&gt;
&lt;br /&gt;
== REST Requests ==&lt;br /&gt;
For REST Request substitution, the embedded URL is fetched, parsed for a single [[LLSD]] document which is embedded inside the curly braces. &lt;br /&gt;
&lt;br /&gt;
The simple syntax is an opening curly brace &#039;{&#039;, followed by the URL, and terminated with a closing curly brace &#039;}&#039;. The document at the url is parsed and treated as a string. Containers, the undefined element, and non-parseable documents are considered errors.&lt;br /&gt;
&lt;br /&gt;
For http request, no instructions to the protocol means to perform a normal GET.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Rest Request Substitution Examples&lt;br /&gt;
! Format !! Results&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;{http://gridtool.agni.lindenlab.com/agents/online-now}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| 58582&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;{http://blondie.lindenlab.com/lookup/agentname/phoenix/linden||agent-id}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
| 3c115e51-04f4-523c-9fa6-98aff1034730&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Supported protocols: http, https &lt;br /&gt;
&lt;br /&gt;
We should probably support file.&lt;br /&gt;
&lt;br /&gt;
== Recursive Substitution ==&lt;br /&gt;
In theory, this grammar can be used recursively, though only python currently supports this feature.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|+ Formating Examples&lt;br /&gt;
! Format&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;nowiki&amp;gt;{http://sim1028.{$grid}.{$domain}/agent/{$agent-id}/location}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| {{$node}{$domain}}&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Syntax Specification =&lt;br /&gt;
The full syntax is an opening curly brace &#039;{&#039;, followed by the URL, followed by a vline &#039;|&#039;, followed by protocol specific instructions, followed by a &#039;vline&#039;, followed by a path to follow through the document to the element which will be treated as a string. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
russ-statement : open-russ substitution close-russ&lt;br /&gt;
open-russ: &#039;{&#039;&lt;br /&gt;
close-russ: &#039;}&#039;&lt;br /&gt;
substituion: string-substitution| query-string-substitution | url-substitution | function-substitution&lt;br /&gt;
string-substition: &#039;$&#039; llsd-key&lt;br /&gt;
query-string-substition: &#039;%&#039; llsd-key&lt;br /&gt;
function-substitution: &#039;!&#039; function-name&lt;br /&gt;
function-name: llsd-key&lt;br /&gt;
url-substitution: url [ vline [ url-parameters ] vline llsd-path]&lt;br /&gt;
url: protocol &#039;:&#039; (normal url authority &amp;amp; host &amp;amp; path &amp;amp; parameters &amp;amp; opaque parts)&lt;br /&gt;
protocol: &#039;http&#039; | &#039;https&#039;&lt;br /&gt;
vline: &#039;|&#039;&lt;br /&gt;
url-parameters: verb [ body ]&lt;br /&gt;
verb: &#039;GET&#039; | &#039;PUT&#039; | &#039;POST&#039; | &#039;DELETE&#039;&lt;br /&gt;
body: ???&lt;br /&gt;
llsd-path: segment * [ &amp;quot;/&amp;quot; segment ]&lt;br /&gt;
segment: llsd-key&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Please note that the following elements in the syntax rules are not well defined:&lt;br /&gt;
* llsd-key&lt;br /&gt;
* body&lt;br /&gt;
* function-name&lt;br /&gt;
&lt;br /&gt;
= Implementations =&lt;br /&gt;
== python ==&lt;br /&gt;
Our indra python libs have a russ implementation in russ.py which supports:&lt;br /&gt;
* string substitution&lt;br /&gt;
* query string substitution&lt;br /&gt;
* url substitution&lt;br /&gt;
* recursive substitution&lt;br /&gt;
&lt;br /&gt;
== c++ ==&lt;br /&gt;
In indra/llmessage libs has a russ implementation inside of the LLServiceBuilder class which supports:&lt;br /&gt;
* string substitution&lt;br /&gt;
* url substitution&lt;br /&gt;
&lt;br /&gt;
== perl ==&lt;br /&gt;
In &amp;lt;code&amp;gt;Indra::WebServices&amp;lt;/code&amp;gt;, you can call &amp;lt;code&amp;gt;buildService($service_name)&amp;lt;/code&amp;gt; to make a client to that service. The current implementation supports:&lt;br /&gt;
* string substitution&lt;br /&gt;
* query string substitution&lt;br /&gt;
* recursive substitution&lt;/div&gt;</summary>
		<author><name>Phoenix Linden</name></author>
	</entry>
</feed>