Parcourir la source

* This is Melanie's XEngine script engine. I've not tested this real well, however, it's confirmed to compile and OpenSimulator to run successfully without this script engine active.

Teravus Ovares il y a 16 ans
Parent
commit
1a47ff8094
39 fichiers modifiés avec 21507 ajouts et 0 suppressions
  1. 270 0
      OpenSim/Region/ScriptEngine/XEngine/AsyncCommandManager.cs
  2. 127 0
      OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/Dataserver.cs
  3. 76 0
      OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/Eventstream.cs
  4. 89 0
      OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/HttpRequest.cs
  5. 91 0
      OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/Listener.cs
  6. 391 0
      OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/SensorRepeat.cs
  7. 163 0
      OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/Timer.cs
  8. 115 0
      OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/XmlRequest.cs
  9. 515 0
      OpenSim/Region/ScriptEngine/XEngine/Compiler.cs
  10. 293 0
      OpenSim/Region/ScriptEngine/XEngine/EventManager.cs
  11. 136 0
      OpenSim/Region/ScriptEngine/XEngine/Executor.cs
  12. 181 0
      OpenSim/Region/ScriptEngine/XEngine/ExecutorBase.cs
  13. 363 0
      OpenSim/Region/ScriptEngine/XEngine/LSL2CSConverter.cs
  14. 6474 0
      OpenSim/Region/ScriptEngine/XEngine/LSL_ScriptCommands.cs
  15. 553 0
      OpenSim/Region/ScriptEngine/XEngine/OSSL_ScriptCommands.cs
  16. 65 0
      OpenSim/Region/ScriptEngine/XEngine/Script/AssemblyResolver.cs
  17. 2393 0
      OpenSim/Region/ScriptEngine/XEngine/Script/BuiltIn_Commands_BaseClass.cs
  18. 653 0
      OpenSim/Region/ScriptEngine/XEngine/Script/ILSL_ScriptCommands.cs
  19. 68 0
      OpenSim/Region/ScriptEngine/XEngine/Script/IOSSL_ScriptCommands.cs
  20. 46 0
      OpenSim/Region/ScriptEngine/XEngine/Script/IScript.cs
  21. 1411 0
      OpenSim/Region/ScriptEngine/XEngine/Script/LSL_Types.cs
  22. 1435 0
      OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
  23. 61 0
      ThirdParty/SmartThreadPool/AssemblyInfo.cs
  24. 223 0
      ThirdParty/SmartThreadPool/CallerThreadContext.cs
  25. 81 0
      ThirdParty/SmartThreadPool/Exceptions.cs
  26. 271 0
      ThirdParty/SmartThreadPool/Interfaces.cs
  27. 240 0
      ThirdParty/SmartThreadPool/PriorityQueue.cs
  28. 352 0
      ThirdParty/SmartThreadPool/STPPerformanceCounter.cs
  29. 99 0
      ThirdParty/SmartThreadPool/STPStartInfo.cs
  30. 1438 0
      ThirdParty/SmartThreadPool/SmartThreadPool.cs
  31. 99 0
      ThirdParty/SmartThreadPool/WIGStartInfo.cs
  32. 1035 0
      ThirdParty/SmartThreadPool/WorkItem.cs
  33. 333 0
      ThirdParty/SmartThreadPool/WorkItemFactory.cs
  34. 102 0
      ThirdParty/SmartThreadPool/WorkItemInfo.cs
  35. 512 0
      ThirdParty/SmartThreadPool/WorkItemsGroup.cs
  36. 600 0
      ThirdParty/SmartThreadPool/WorkItemsQueue.cs
  37. 22 0
      ThirdPartyLicenses/SmartThreadPool.txt
  38. 37 0
      bin/OpenSim.ini.example
  39. 94 0
      prebuild.xml

+ 270 - 0
OpenSim/Region/ScriptEngine/XEngine/AsyncCommandManager.cs

@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Threading;
+using libsecondlife;
+using OpenSim.Framework;
+using OpenSim.Region.Environment.Interfaces;
+using OpenSim.Region.ScriptEngine.XEngine.AsyncCommandPlugins;
+using Timer=OpenSim.Region.ScriptEngine.XEngine.AsyncCommandPlugins.Timer;
+using Dataserver=OpenSim.Region.ScriptEngine.XEngine.AsyncCommandPlugins.Dataserver;
+
+namespace OpenSim.Region.ScriptEngine.XEngine
+{
+    /// <summary>
+    /// Handles LSL commands that takes long time and returns an event, for example timers, HTTP requests, etc.
+    /// </summary>
+    public class AsyncCommandManager
+    {
+        private static Thread cmdHandlerThread;
+        private static int cmdHandlerThreadCycleSleepms;
+
+        public XEngine m_ScriptEngine;
+
+        public Dataserver m_Dataserver;
+        public Timer m_Timer;
+        public HttpRequest m_HttpRequest;
+        public Listener m_Listener;
+        public SensorRepeat m_SensorRepeat;
+        public XmlRequest m_XmlRequest;
+
+        public AsyncCommandManager(XEngine _ScriptEngine)
+        {
+            m_ScriptEngine = _ScriptEngine;
+            ReadConfig();
+
+            // Create instances of all plugins
+            m_Dataserver = new Dataserver(this);
+            m_Timer = new Timer(this);
+            m_HttpRequest = new HttpRequest(this);
+            m_Listener = new Listener(this);
+            m_SensorRepeat = new SensorRepeat(this);
+            m_XmlRequest = new XmlRequest(this);
+
+            StartThread();
+        }
+
+        private static void StartThread()
+        {
+            if (cmdHandlerThread == null)
+            {
+                // Start the thread that will be doing the work
+                cmdHandlerThread = new Thread(CmdHandlerThreadLoop);
+                cmdHandlerThread.Name = "AsyncLSLCmdHandlerThread";
+                cmdHandlerThread.Priority = ThreadPriority.BelowNormal;
+                cmdHandlerThread.IsBackground = true;
+                cmdHandlerThread.Start();
+                ThreadTracker.Add(cmdHandlerThread);
+            }
+        }
+
+        public void ReadConfig()
+        {
+            cmdHandlerThreadCycleSleepms = m_ScriptEngine.ScriptConfigSource.GetInt("AsyncLLCommandLoopms", 100);
+        }
+
+        ~AsyncCommandManager()
+        {
+            // Shut down thread
+            try
+            {
+                if (cmdHandlerThread != null)
+                {
+                    if (cmdHandlerThread.IsAlive == true)
+                    {
+                        cmdHandlerThread.Abort();
+                        //cmdHandlerThread.Join();
+                    }
+                }
+            }
+            catch
+            {
+            }
+        }
+
+        private static void CmdHandlerThreadLoop()
+        {
+            while (true)
+            {
+                try
+                {
+                    while (true)
+                    {
+                        Thread.Sleep(cmdHandlerThreadCycleSleepms);
+
+                        foreach (XEngine xe in XEngine.ScriptEngines)
+                        {
+                            xe.m_ASYNCLSLCommandManager.DoOneCmdHandlerPass();
+                        }
+                    }
+                }
+                catch
+                {
+                }
+            }
+        }
+
+        internal void DoOneCmdHandlerPass()
+        {
+            // Check timers
+            m_Timer.CheckTimerEvents();
+            // Check HttpRequests
+            m_HttpRequest.CheckHttpRequests();
+            // Check XMLRPCRequests
+            m_XmlRequest.CheckXMLRPCRequests();
+            // Check Listeners
+            m_Listener.CheckListeners();
+            // Check Sensors
+            m_SensorRepeat.CheckSenseRepeaterEvents();
+            // Check dataserver
+            m_Dataserver.ExpireRequests();
+        }
+
+        /// <summary>
+        /// Remove a specific script (and all its pending commands)
+        /// </summary>
+        /// <param name="localID"></param>
+        /// <param name="itemID"></param>
+        public void RemoveScript(uint localID, LLUUID itemID)
+        {
+            // Remove a specific script
+
+            // Remove dataserver events
+            m_Dataserver.RemoveEvents(localID, itemID);
+
+            // Remove from: Timers
+            m_Timer.UnSetTimerEvents(localID, itemID);
+
+            // Remove from: HttpRequest
+            IHttpRequests iHttpReq =
+                m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
+            iHttpReq.StopHttpRequest(localID, itemID);
+
+            IWorldComm comms = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+            comms.DeleteListener(itemID);
+
+            IXMLRPC xmlrpc = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
+            xmlrpc.DeleteChannels(itemID);
+            xmlrpc.CancelSRDRequests(itemID);
+
+            // Remove Sensors
+            m_SensorRepeat.UnSetSenseRepeaterEvents(localID, itemID);
+
+        }
+
+        public Object[] GetSerializationData(LLUUID itemID)
+        {
+            List<Object> data = new List<Object>();
+
+            Object[] listeners=m_Listener.GetSerializationData(itemID);
+            if(listeners.Length > 0)
+            {
+                data.Add("listener");
+                data.Add(listeners.Length);
+                data.AddRange(listeners);
+            }
+
+            Object[] timers=m_Timer.GetSerializationData(itemID);
+            if(timers.Length > 0)
+            {
+                data.Add("timer");
+                data.Add(timers.Length);
+                data.AddRange(timers);
+            }
+
+            Object[] sensors=m_SensorRepeat.GetSerializationData(itemID);
+            if(sensors.Length > 0)
+            {
+                data.Add("sensor");
+                data.Add(sensors.Length);
+                data.AddRange(sensors);
+            }
+
+            return data.ToArray();
+        }
+
+        public void CreateFromData(uint localID, LLUUID itemID, LLUUID hostID,
+                Object[] data)
+        {
+            int idx=0;
+            int len;
+
+            while(idx < data.Length)
+            {
+                string type = data[idx].ToString();
+                len = (int)data[idx+1];
+                idx+=2;
+
+                if(len > 0)
+                {
+                    Object[] item = new Object[len];
+                    Array.Copy(data, idx, item, 0, len);
+
+                    idx+=len;
+
+                    switch(type)
+                    {
+                    case "listener":
+                        m_Listener.CreateFromData(localID, itemID, hostID,
+                                item);
+                        break;
+                    case "timer":
+                        m_Timer.CreateFromData(localID, itemID, hostID, item);
+                        break;
+                    case "sensor":
+                        m_SensorRepeat.CreateFromData(localID, itemID, hostID,
+                                item);
+                        break;
+                    }
+                }
+            }
+        }
+
+        #region Check llRemoteData channels
+
+
+        #endregion
+
+        #region Check llListeners
+
+
+        #endregion
+
+        /// <summary>
+        /// If set to true then threads and stuff should try to make a graceful exit
+        /// </summary>
+        public bool PleaseShutdown
+        {
+            get { return _PleaseShutdown; }
+            set { _PleaseShutdown = value; }
+        }
+        private bool _PleaseShutdown = false;
+    }
+}

+ 127 - 0
OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/Dataserver.cs

@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using libsecondlife;
+using OpenSim.Region.ScriptEngine.XEngine.Script;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.AsyncCommandPlugins
+{
+    public class Dataserver
+    {
+        public AsyncCommandManager m_CmdManager;
+
+        private Dictionary<string, DataserverRequest> DataserverRequests =
+                new Dictionary<string, DataserverRequest>();
+
+        public Dataserver(AsyncCommandManager CmdManager)
+        {
+            m_CmdManager = CmdManager;
+        }
+
+        private class DataserverRequest
+        {
+            public uint localID;
+            public LLUUID itemID;
+
+            public LLUUID ID;
+            public string handle;
+
+            public DateTime startTime;
+        }
+
+        public LLUUID RegisterRequest(uint localID, LLUUID itemID,
+                string identifier)
+        {
+            lock(DataserverRequests)
+            {
+                if(DataserverRequests.ContainsKey(identifier))
+                    return LLUUID.Zero;
+
+                DataserverRequest ds = new DataserverRequest();
+
+                ds.localID = localID;
+                ds.itemID = itemID;
+
+                ds.ID = LLUUID.Random();
+                ds.handle = identifier;
+
+                ds.startTime = DateTime.Now;
+
+                DataserverRequests[identifier]=ds;
+
+                return ds.ID;
+            }
+        }
+
+        public void DataserverReply(string identifier, string reply)
+        {
+            DataserverRequest ds;
+
+            lock(DataserverRequests)
+            {
+                if(!DataserverRequests.ContainsKey(identifier))
+                    return;
+                
+                ds=DataserverRequests[identifier];
+                DataserverRequests.Remove(identifier);
+            }
+
+            m_CmdManager.m_ScriptEngine.PostObjectEvent(ds.localID,
+                    new XEventParams( "dataserver", new Object[]
+                            { new LSL_Types.LSLString(ds.ID.ToString()),
+                            new LSL_Types.LSLString(reply)},
+                    new XDetectParams[0]));
+        }
+
+        public void RemoveEvents(uint localID, LLUUID itemID)
+        {
+            lock(DataserverRequests)
+            {
+                foreach (DataserverRequest ds in new List<DataserverRequest>(DataserverRequests.Values))
+                {
+                    if(ds.itemID == itemID)
+                        DataserverRequests.Remove(ds.handle);
+                }
+            }
+        }
+
+        public void ExpireRequests()
+        {
+            lock(DataserverRequests)
+            {
+                foreach (DataserverRequest ds in new List<DataserverRequest>(DataserverRequests.Values))
+                {
+                    if(ds.startTime > DateTime.Now.AddSeconds(30))
+                        DataserverRequests.Remove(ds.handle);
+                }
+            }
+        }
+    }
+}

+ 76 - 0
OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/Eventstream.cs

@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using libsecondlife;
+using OpenSim.Region.Environment.Scenes;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.AsyncCommandPlugins
+{
+    public class Eventstream
+    {
+        public AsyncCommandManager m_CmdManager;
+
+        private class Event
+        {
+            public uint LocalID;
+            public string EventName;
+            public Dictionary<LLUUID, XDetectParams> DetectParams;
+        }
+
+        private Dictionary<uint, Dictionary<string, Event> > m_Events =
+                new Dictionary<uint, Dictionary<string, Event> >();
+
+        public Eventstream(AsyncCommandManager CmdManager)
+        {
+            m_CmdManager = CmdManager;
+        }
+
+        public void AddObjectEvent(uint localID, string eventName, XDetectParams det)
+        {
+            SceneObjectPart part = m_CmdManager.m_ScriptEngine.World.
+                    GetSceneObjectPart(localID);
+
+            if(part == null) // Can't register events for non-prims
+                return;
+
+            if(!part.ContainsScripts())
+                return;
+
+        }
+
+        public void RemoveObjectEvent(uint localID, string eventName, LLUUID id)
+        {
+        }
+
+        public void RemoveObjects(uint localID)
+        {
+        }
+    }
+}

+ 89 - 0
OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/HttpRequest.cs

@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using OpenSim.Region.Environment.Interfaces;
+using OpenSim.Region.Environment.Modules.Scripting.HttpRequest;
+using OpenSim.Region.ScriptEngine.XEngine.Script;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.AsyncCommandPlugins
+{
+    public class HttpRequest
+    {
+        public AsyncCommandManager m_CmdManager;
+
+        public HttpRequest(AsyncCommandManager CmdManager)
+        {
+            m_CmdManager = CmdManager;
+        }
+
+        public void CheckHttpRequests()
+        {
+            if (m_CmdManager.m_ScriptEngine.World == null)
+                return;
+
+            IHttpRequests iHttpReq =
+                m_CmdManager.m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
+
+            HttpRequestClass httpInfo = null;
+
+            if (iHttpReq != null)
+                httpInfo = iHttpReq.GetNextCompletedRequest();
+
+            while (httpInfo != null)
+            {
+                //m_ScriptEngine.Log.Info("[AsyncLSL]:" + httpInfo.response_body + httpInfo.status);
+
+                // Deliver data to prim's remote_data handler
+                //
+                // TODO: Returning null for metadata, since the lsl function
+                // only returns the byte for HTTP_BODY_TRUNCATED, which is not
+                // implemented here yet anyway.  Should be fixed if/when maxsize
+                // is supported
+
+                iHttpReq.RemoveCompletedRequest(httpInfo.reqID);
+
+                object[] resobj = new object[]
+                {
+                    new LSL_Types.LSLString(httpInfo.reqID.ToString()),
+                    new LSL_Types.LSLInteger(httpInfo.status),
+                    new LSL_Types.list(),
+                    new LSL_Types.LSLString(httpInfo.response_body)
+                };
+
+                foreach (XEngine xe in XEngine.ScriptEngines)
+                {
+                    if(xe.PostObjectEvent(httpInfo.localID,
+                            new XEventParams("http_response",
+                            resobj, new XDetectParams[0])))
+                        break;
+                }
+                httpInfo = iHttpReq.GetNextCompletedRequest();
+            }
+        }
+    }
+}

+ 91 - 0
OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/Listener.cs

@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using libsecondlife;
+using OpenSim.Region.Environment.Interfaces;
+using OpenSim.Region.Environment.Modules.Scripting.WorldComm;
+using OpenSim.Region.ScriptEngine.XEngine.Script;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.AsyncCommandPlugins
+{
+    public class Listener
+    {
+        // private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+        public AsyncCommandManager m_CmdManager;
+
+        public Listener(AsyncCommandManager CmdManager)
+        {
+            m_CmdManager = CmdManager;
+        }
+
+        public void CheckListeners()
+        {
+            if (m_CmdManager.m_ScriptEngine.World == null)
+                return;
+            IWorldComm comms = m_CmdManager.m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+
+            if (comms != null)
+            {
+                while (comms.HasMessages())
+                {
+                    ListenerInfo lInfo = comms.GetNextMessage();
+
+                    //Deliver data to prim's listen handler
+                    object[] resobj = new object[]
+                    {
+                        new LSL_Types.LSLInteger(lInfo.GetChannel()),
+                        new LSL_Types.LSLString(lInfo.GetName()),
+                        new LSL_Types.LSLString(lInfo.GetID().ToString()),
+                        new LSL_Types.LSLString(lInfo.GetMessage())
+                    };
+
+                    m_CmdManager.m_ScriptEngine.PostScriptEvent(
+                            lInfo.GetItemID(), new XEventParams(
+                            "listen", resobj,
+                            new XDetectParams[0]));
+                }
+            }
+        }
+
+        public Object[] GetSerializationData(LLUUID itemID)
+        {
+            IWorldComm comms = m_CmdManager.m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+
+            return comms.GetSerializationData(itemID);
+        }
+
+        public void CreateFromData(uint localID, LLUUID itemID, LLUUID hostID,
+                Object[] data)
+        {
+            IWorldComm comms = m_CmdManager.m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+
+            comms.CreateFromData(localID, itemID, hostID, data);
+        }
+    }
+}

+ 391 - 0
OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/SensorRepeat.cs

@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using libsecondlife;
+using OpenSim.Framework;
+using OpenSim.Region.Environment.Scenes;
+using OpenSim.Region.ScriptEngine.XEngine.Script;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.AsyncCommandPlugins
+{
+    public class SensorRepeat
+    {
+        public AsyncCommandManager m_CmdManager;
+
+        public SensorRepeat(AsyncCommandManager CmdManager)
+        {
+            m_CmdManager = CmdManager;
+        }
+
+        public Dictionary<uint, Dictionary<LLUUID, LSL_Types.list>> SenseEvents =
+            new Dictionary<uint, Dictionary<LLUUID, LSL_Types.list>>();
+        private Object SenseLock = new Object();
+
+        //
+        // SenseRepeater and Sensors
+        //
+        private class SenseRepeatClass
+        {
+            public uint localID;
+            public LLUUID itemID;
+            public double interval;
+            public DateTime next;
+
+            public string name;
+            public LLUUID keyID;
+            public int type;
+            public double range;
+            public double arc;
+            public SceneObjectPart host;
+        }
+
+        private List<SenseRepeatClass> SenseRepeaters = new List<SenseRepeatClass>();
+        private object SenseRepeatListLock = new object();
+
+        public void SetSenseRepeatEvent(uint m_localID, LLUUID m_itemID,
+            string name, LLUUID keyID, int type, double range, double arc, double sec, SceneObjectPart host)
+        {
+            Console.WriteLine("SetSensorEvent");
+
+            // Always remove first, in case this is a re-set
+            UnSetSenseRepeaterEvents(m_localID, m_itemID);
+            if (sec == 0) // Disabling timer
+                return;
+
+            // Add to timer
+            SenseRepeatClass ts = new SenseRepeatClass();
+            ts.localID = m_localID;
+            ts.itemID = m_itemID;
+            ts.interval = sec;
+            ts.name = name;
+            ts.keyID = keyID;
+            ts.type = type;
+            ts.range = range;
+            ts.arc = arc;
+            ts.host = host;
+
+            ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
+            lock (SenseRepeatListLock)
+            {
+                SenseRepeaters.Add(ts);
+            }
+        }
+
+        public void UnSetSenseRepeaterEvents(uint m_localID, LLUUID m_itemID)
+        {
+            // Remove from timer
+            lock (SenseRepeatListLock)
+            {
+                List<SenseRepeatClass> NewSensors = new List<SenseRepeatClass>();
+                foreach (SenseRepeatClass ts in SenseRepeaters)
+                {
+                    if (ts.localID != m_localID && ts.itemID != m_itemID)
+                    {
+                        NewSensors.Add(ts);
+                    }
+                }
+                SenseRepeaters.Clear();
+                SenseRepeaters = NewSensors;
+            }
+        }
+
+        public void CheckSenseRepeaterEvents()
+        {
+            // Nothing to do here?
+            if (SenseRepeaters.Count == 0)
+                return;
+
+            lock (SenseRepeatListLock)
+            {
+                // Go through all timers
+                foreach (SenseRepeatClass ts in SenseRepeaters)
+                {
+                    // Time has passed?
+                    if (ts.next.ToUniversalTime() < DateTime.Now.ToUniversalTime())
+                    {
+                        SensorSweep(ts);
+                        // set next interval
+                        ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
+                    }
+                }
+            } // lock
+        }
+
+        public void SenseOnce(uint m_localID, LLUUID m_itemID,
+                              string name, LLUUID keyID, int type,
+                              double range, double arc, SceneObjectPart host)
+        {
+            // Add to timer
+            SenseRepeatClass ts = new SenseRepeatClass();
+            ts.localID = m_localID;
+            ts.itemID = m_itemID;
+            ts.interval = 0;
+            ts.name = name;
+            ts.keyID = keyID;
+            ts.type = type;
+            ts.range = range;
+            ts.arc = arc;
+            ts.host = host;
+            SensorSweep(ts);
+        }
+
+        public LSL_Types.list GetSensorList(uint m_localID, LLUUID m_itemID)
+        {
+            lock (SenseLock)
+            {
+                Dictionary<LLUUID, LSL_Types.list> Obj = null;
+                if (!SenseEvents.TryGetValue(m_localID, out Obj))
+                {
+                    m_CmdManager.m_ScriptEngine.Log.Info("[AsyncLSL]: GetSensorList missing localID: " + m_localID);
+                    return null;
+                }
+                lock (Obj)
+                {
+                    // Get script
+                    LSL_Types.list SenseList = null;
+                    if (!Obj.TryGetValue(m_itemID, out SenseList))
+                    {
+                        m_CmdManager.m_ScriptEngine.Log.Info("[AsyncLSL]: GetSensorList missing itemID: " + m_itemID);
+                        return null;
+                    }
+                    return SenseList;
+                }
+            }
+        }
+
+        private void SensorSweep(SenseRepeatClass ts)
+        {
+            //m_ScriptEngine.Log.Info("[AsyncLSL]:Enter SensorSweep");
+            SceneObjectPart SensePoint = ts.host;
+
+            if (SensePoint == null)
+            {
+                //m_ScriptEngine.Log.Info("[AsyncLSL]: Enter SensorSweep (SensePoint == null) for "+ts.itemID.ToString());
+                return;
+            }
+            //m_ScriptEngine.Log.Info("[AsyncLSL]: Enter SensorSweep Scan");
+
+            LLVector3 sensorPos = SensePoint.AbsolutePosition;
+            LLVector3 regionPos = new LLVector3(m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocX * Constants.RegionSize, m_CmdManager.m_ScriptEngine.World.RegionInfo.RegionLocY * Constants.RegionSize, 0);
+            LLVector3 fromRegionPos = sensorPos + regionPos;
+
+            LLQuaternion q = SensePoint.RotationOffset;
+            LSL_Types.Quaternion r = new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
+            LSL_Types.Vector3 forward_dir = (new LSL_Types.Vector3(1, 0, 0) * r);
+            double mag_fwd = LSL_Types.Vector3.Mag(forward_dir);
+
+            // Here we should do some smart culling ...
+            // math seems quicker than strings so try that first
+            LSL_Types.list SensedObjects = new LSL_Types.list();
+            LSL_Types.Vector3 ZeroVector = new LSL_Types.Vector3(0, 0, 0);
+
+            foreach (EntityBase ent in m_CmdManager.m_ScriptEngine.World.Entities.Values)
+            {
+                LLVector3 toRegionPos = ent.AbsolutePosition + regionPos;
+                double dis = Math.Abs((double)Util.GetDistanceTo(toRegionPos, fromRegionPos));
+                if (dis <= ts.range)
+                {
+                    // In Range, is it the right Type ?
+                    int objtype = 0;
+
+                    if (m_CmdManager.m_ScriptEngine.World.GetScenePresence(ent.UUID) != null) objtype |= 0x01; // actor
+                    if (ent.Velocity.Equals(ZeroVector))
+                        objtype |= 0x04; // passive non-moving
+                    else
+                        objtype |= 0x02; // active moving
+                    if (ent is IScript) objtype |= 0x08; // Scripted. It COULD have one hidden ...
+
+                    if (((ts.type & objtype) != 0) || ((ts.type & objtype) == ts.type))
+                    {
+                        // docs claim AGENT|ACTIVE should find agent objects OR active objects
+                        // so the bitwise AND with object type should be non-zero
+
+                        // Right type too, what about the other params , key and name ?
+                        bool keep = true;
+                        if (ts.arc < Math.PI)
+                        {
+                            // not omni-directional. Can you see it ?
+                            // vec forward_dir = llRot2Fwd(llGetRot())
+                            // vec obj_dir = toRegionPos-fromRegionPos
+                            // dot=dot(forward_dir,obj_dir)
+                            // mag_fwd = mag(forward_dir)
+                            // mag_obj = mag(obj_dir)
+                            // ang = acos(dot /(mag_fwd*mag_obj))
+                            double ang_obj = 0;
+                            try
+                            {
+                                LLVector3 diff = toRegionPos - fromRegionPos;
+                                LSL_Types.Vector3 obj_dir = new LSL_Types.Vector3(diff.X, diff.Y, diff.Z);
+                                double dot = LSL_Types.Vector3.Dot(forward_dir, obj_dir);
+                                double mag_obj = LSL_Types.Vector3.Mag(obj_dir);
+                                ang_obj = Math.Acos(dot / (mag_fwd * mag_obj));
+                            }
+                            catch
+                            {
+                            }
+
+                            if (ang_obj > ts.arc) keep = false;
+                        }
+
+                        if (keep && (ts.keyID != LLUUID.Zero) && (ts.keyID != ent.UUID))
+                        {
+                            keep = false;
+                        }
+
+                        if (keep && (ts.name.Length > 0))
+                        {
+                            string avatarname=null;
+                            string objectname=null;
+                            string entname =ent.Name;
+
+                            // try avatar username surname
+                            UserProfileData profile = m_CmdManager.m_ScriptEngine.World.CommsManager.UserService.GetUserProfile(ent.UUID);
+                            if (profile != null)
+                            {
+                               avatarname = profile.FirstName + " " + profile.SurName;
+                            }
+                            // try an scene object
+                            SceneObjectPart SOP = m_CmdManager.m_ScriptEngine.World.GetSceneObjectPart(ent.UUID);
+                            if (SOP != null)
+                            {
+                                objectname = SOP.Name;
+                            }
+
+                            if ((ts.name != entname) && (ts.name != avatarname) && (ts.name != objectname))
+                            {
+                               keep = false;
+                            }
+                        }
+
+                        if (keep == true) SensedObjects.Add(ent.UUID);
+                    }
+                }
+            }
+            //m_ScriptEngine.Log.Info("[AsyncLSL]: Enter SensorSweep SenseLock");
+
+            lock (SenseLock)
+            {
+                // Create object if it doesn't exist
+                if (SenseEvents.ContainsKey(ts.localID) == false)
+                {
+                    SenseEvents.Add(ts.localID, new Dictionary<LLUUID, LSL_Types.list>());
+                }
+                // clear if previous traces exist
+                Dictionary<LLUUID, LSL_Types.list> Obj;
+                SenseEvents.TryGetValue(ts.localID, out Obj);
+                if (Obj.ContainsKey(ts.itemID) == true)
+                    Obj.Remove(ts.itemID);
+
+                // note list may be zero length
+                Obj.Add(ts.itemID, SensedObjects);
+
+                if (SensedObjects.Length == 0)
+                {
+                    // send a "no_sensor"
+                    // Add it to queue
+                    m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
+                            new XEventParams("no_sensor", new Object[0],
+                            new XDetectParams[0]));
+                }
+                else
+                {
+                    XDetectParams[] detect =
+                            new XDetectParams[SensedObjects.Length];
+
+                    int idx;
+                    for(idx = 0 ; idx < SensedObjects.Length; idx++)
+                    {
+                        detect[idx].Key=(LLUUID)(SensedObjects.Data[idx]);
+                    }
+
+                    m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
+                            new XEventParams("sensor",
+                            new Object[] {
+                            new LSL_Types.LSLInteger(SensedObjects.Length) },
+                            detect));
+                }
+            }
+        }
+
+        public Object[] GetSerializationData(LLUUID itemID)
+        {
+            List<Object> data = new List<Object>();
+
+            foreach (SenseRepeatClass ts in SenseRepeaters)
+            {
+                if(ts.itemID == itemID)
+                {
+                    data.Add(ts.interval);
+                    data.Add(ts.name);
+                    data.Add(ts.keyID);
+                    data.Add(ts.type);
+                    data.Add(ts.range);
+                    data.Add(ts.arc);
+                }
+            }
+            return data.ToArray();
+        }
+
+        public void CreateFromData(uint localID, LLUUID itemID, LLUUID objectID,
+                Object[] data)
+        {
+            SceneObjectPart part =
+                    m_CmdManager.m_ScriptEngine.World.GetSceneObjectPart(
+                    objectID);
+
+            if(part == null)
+                return;
+
+            int idx=0;
+
+            while(idx < data.Length)
+            {
+                SenseRepeatClass ts = new SenseRepeatClass();
+
+                ts.localID = localID;
+                ts.itemID = itemID;
+
+                ts.interval = (double)data[idx];
+                ts.name = (string)data[idx+1];
+                ts.keyID = (LLUUID)data[idx+2];
+                ts.type = (int)data[idx+3];
+                ts.range = (double)data[idx+4];
+                ts.arc = (double)data[idx+5];
+                ts.host = part;
+
+                ts.next =
+                        DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
+
+                SenseRepeaters.Add(ts);
+                idx += 6;
+            }
+        }
+
+    }
+}

+ 163 - 0
OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/Timer.cs

@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using libsecondlife;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.AsyncCommandPlugins
+{
+    public class Timer
+    {
+        public AsyncCommandManager m_CmdManager;
+
+        public Timer(AsyncCommandManager CmdManager)
+        {
+            m_CmdManager = CmdManager;
+        }
+
+        //
+        // TIMER
+        //
+        private class TimerClass
+        {
+            public uint localID;
+            public LLUUID itemID;
+            //public double interval;
+            public long interval;
+            //public DateTime next;
+            public long next;
+        }
+
+        private List<TimerClass> Timers = new List<TimerClass>();
+        private object TimerListLock = new object();
+
+        public void SetTimerEvent(uint m_localID, LLUUID m_itemID, double sec)
+        {
+            Console.WriteLine("SetTimerEvent");
+
+            // Always remove first, in case this is a re-set
+            UnSetTimerEvents(m_localID, m_itemID);
+            if (sec == 0) // Disabling timer
+                return;
+
+            // Add to timer
+            TimerClass ts = new TimerClass();
+            ts.localID = m_localID;
+            ts.itemID = m_itemID;
+            ts.interval = Convert.ToInt64(sec * 10000000); // How many 100 nanoseconds (ticks) should we wait
+            //       2193386136332921 ticks
+            //       219338613 seconds
+
+            //ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
+            ts.next = DateTime.Now.Ticks + ts.interval;
+            lock (TimerListLock)
+            {
+                Timers.Add(ts);
+            }
+        }
+
+        public void UnSetTimerEvents(uint m_localID, LLUUID m_itemID)
+        {
+            // Remove from timer
+            lock (TimerListLock)
+            {
+                foreach (TimerClass ts in new ArrayList(Timers))
+                {
+                    if (ts.localID == m_localID && ts.itemID == m_itemID)
+                        Timers.Remove(ts);
+                }
+            }
+        }
+
+        public void CheckTimerEvents()
+        {
+            // Nothing to do here?
+            if (Timers.Count == 0)
+                return;
+
+            lock (TimerListLock)
+            {
+                // Go through all timers
+                foreach (TimerClass ts in Timers)
+                {
+                    // Time has passed?
+                    if (ts.next < DateTime.Now.Ticks)
+                    {
+                        //                        Console.WriteLine("Time has passed: Now: " + DateTime.Now.Ticks + ", Passed: " + ts.next);
+                        // Add it to queue
+                        m_CmdManager.m_ScriptEngine.PostScriptEvent(ts.itemID,
+                                new XEventParams("timer", new Object[0],
+                                new XDetectParams[0]));
+                        // set next interval
+
+                        //ts.next = DateTime.Now.ToUniversalTime().AddSeconds(ts.interval);
+                        ts.next = DateTime.Now.Ticks + ts.interval;
+                    }
+                }
+            }
+        }
+
+        public Object[] GetSerializationData(LLUUID itemID)
+        {
+            List<Object> data = new List<Object>();
+
+            lock (TimerListLock)
+            {
+                foreach (TimerClass ts in Timers)
+                {
+                    if(ts.itemID == itemID)
+                    {
+                        data.Add(ts.interval);
+                        data.Add(ts.next-DateTime.Now.Ticks);
+                    }
+                }
+            }
+            return data.ToArray();
+        }
+
+        public void CreateFromData(uint localID, LLUUID itemID, LLUUID objectID,
+                Object[] data)
+        {
+            int idx=0;
+
+            while(idx < data.Length)
+            {
+                TimerClass ts = new TimerClass();
+
+                ts.localID = localID;
+                ts.itemID = itemID;
+                ts.interval = (long)data[idx];
+                ts.next = DateTime.Now.Ticks + (long)data[idx+1];
+                idx += 2;
+
+                Timers.Add(ts);
+            }
+        }
+    }
+}

+ 115 - 0
OpenSim/Region/ScriptEngine/XEngine/AsyncCommandPlugins/XmlRequest.cs

@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using OpenSim.Region.Environment.Interfaces;
+using OpenSim.Region.Environment.Modules.Scripting.XMLRPC;
+using OpenSim.Region.ScriptEngine.XEngine.Script;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.AsyncCommandPlugins
+{
+    public class XmlRequest
+    {
+        public AsyncCommandManager m_CmdManager;
+
+        public XmlRequest(AsyncCommandManager CmdManager)
+        {
+            m_CmdManager = CmdManager;
+        }
+
+        public void CheckXMLRPCRequests()
+        {
+            if (m_CmdManager.m_ScriptEngine.World == null)
+                return;
+
+            IXMLRPC xmlrpc = m_CmdManager.m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
+
+            if (xmlrpc != null)
+            {
+                RPCRequestInfo rInfo = xmlrpc.GetNextCompletedRequest();
+
+                while (rInfo != null)
+                {
+                    xmlrpc.RemoveCompletedRequest(rInfo.GetMessageID());
+
+                    //Deliver data to prim's remote_data handler
+                    object[] resobj = new object[]
+                    {
+                        new LSL_Types.LSLInteger(2),
+                        new LSL_Types.LSLString(
+                                rInfo.GetChannelKey().ToString()),
+                        new LSL_Types.LSLString(
+                                rInfo.GetMessageID().ToString()),
+                        new LSL_Types.LSLString(String.Empty),
+                        new LSL_Types.LSLInteger(rInfo.GetIntValue()),
+                        new LSL_Types.LSLString(rInfo.GetStrVal())
+                    };
+                    
+                    foreach (XEngine xe in XEngine.ScriptEngines)
+                    {
+                        if(xe.PostScriptEvent(
+                                rInfo.GetItemID(), new XEventParams(
+                                "remote_data", resobj,
+                                new XDetectParams[0])))
+                            break;
+                    }
+
+                    rInfo = xmlrpc.GetNextCompletedRequest();
+                }
+
+                SendRemoteDataRequest srdInfo = xmlrpc.GetNextCompletedSRDRequest();
+
+                while (srdInfo != null)
+                {
+                    xmlrpc.RemoveCompletedSRDRequest(srdInfo.GetReqID());
+
+                    //Deliver data to prim's remote_data handler
+                    object[] resobj = new object[]
+                    {
+                        new LSL_Types.LSLInteger(3),
+                        new LSL_Types.LSLString(srdInfo.channel.ToString()),
+                        new LSL_Types.LSLString(srdInfo.GetReqID().ToString()),
+                        new LSL_Types.LSLString(String.Empty),
+                        new LSL_Types.LSLInteger(srdInfo.idata),
+                        new LSL_Types.LSLString(srdInfo.sdata)
+                    };
+
+                    foreach (XEngine xe in XEngine.ScriptEngines)
+                    {
+                        if(xe.PostScriptEvent(
+                                srdInfo.m_itemID, new XEventParams(
+                                "remote_data", resobj,
+                                new XDetectParams[0])))
+                            break;
+                    }
+
+                    srdInfo = xmlrpc.GetNextCompletedSRDRequest();
+                }
+            }
+        }
+    }
+}

+ 515 - 0
OpenSim/Region/ScriptEngine/XEngine/Compiler.cs

@@ -0,0 +1,515 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.CodeDom.Compiler;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Microsoft.CSharp;
+using Microsoft.JScript;
+using Microsoft.VisualBasic;
+using OpenSim.Region.Environment.Interfaces;
+
+namespace OpenSim.Region.ScriptEngine.XEngine
+{
+    public class Compiler
+    {
+        private static readonly log4net.ILog m_log
+            = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+        // * Uses "LSL2Converter" to convert LSL to C# if necessary.
+        // * Compiles C#-code into an assembly
+        // * Returns assembly name ready for AppDomain load.
+        //
+        // Assembly is compiled using LSL_BaseClass as base. Look at debug C# code file created when LSL script is compiled for full details.
+        //
+
+        internal enum enumCompileType
+        {
+            lsl = 0,
+            cs = 1,
+            vb = 2,
+            js = 3
+        }
+
+        /// <summary>
+        /// This contains number of lines WE use for header when compiling script. User will get error in line x-LinesToRemoveOnError when error occurs.
+        /// </summary>
+        public int LinesToRemoveOnError = 3;
+        private enumCompileType DefaultCompileLanguage;
+        private bool WriteScriptSourceToDebugFile;
+        private bool CompileWithDebugInformation;
+        private Dictionary<string, bool> AllowedCompilers = new Dictionary<string, bool>(StringComparer.CurrentCultureIgnoreCase);
+        private Dictionary<string, enumCompileType> LanguageMapping = new Dictionary<string, enumCompileType>(StringComparer.CurrentCultureIgnoreCase);
+
+        private string FilePrefix;
+        private string ScriptEnginesPath = "ScriptEngines";
+
+        private static LSL2CSConverter LSL_Converter = new LSL2CSConverter();
+        private static CSharpCodeProvider CScodeProvider = new CSharpCodeProvider();
+        private static VBCodeProvider VBcodeProvider = new VBCodeProvider();
+        private static JScriptCodeProvider JScodeProvider = new JScriptCodeProvider();
+
+        private static int instanceID = new Random().Next(0, int.MaxValue);                 // Unique number to use on our compiled files
+        private static UInt64 scriptCompileCounter = 0;                                     // And a counter
+
+        public XEngine m_scriptEngine;
+        public Compiler(XEngine scriptEngine)
+        {
+            m_scriptEngine = scriptEngine;
+            ReadConfig();
+        }
+        public bool in_startup = true;
+        public void ReadConfig()
+        {
+
+            // Get some config
+            WriteScriptSourceToDebugFile = m_scriptEngine.ScriptConfigSource.GetBoolean("WriteScriptSourceToDebugFile", true);
+            CompileWithDebugInformation = m_scriptEngine.ScriptConfigSource.GetBoolean("CompileWithDebugInformation", true);
+
+            // Get file prefix from scriptengine name and make it file system safe:
+            FilePrefix = m_scriptEngine.ScriptEngineName;
+            foreach (char c in Path.GetInvalidFileNameChars())
+            {
+                FilePrefix = FilePrefix.Replace(c, '_');
+            }
+
+            // First time we start? Delete old files
+            if (in_startup)
+            {
+                in_startup = false;
+                DeleteOldFiles();
+            }
+
+            // Map name and enum type of our supported languages
+            LanguageMapping.Add(enumCompileType.cs.ToString(), enumCompileType.cs);
+            LanguageMapping.Add(enumCompileType.vb.ToString(), enumCompileType.vb);
+            LanguageMapping.Add(enumCompileType.lsl.ToString(), enumCompileType.lsl);
+            LanguageMapping.Add(enumCompileType.js.ToString(), enumCompileType.js);
+
+            // Allowed compilers
+            string allowComp = m_scriptEngine.ScriptConfigSource.GetString("AllowedCompilers", "lsl,cs,vb,js");
+            AllowedCompilers.Clear();
+
+#if DEBUG
+            m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Allowed languages: " + allowComp);
+#endif
+
+
+            foreach (string strl in allowComp.Split(','))
+            {
+                string strlan = strl.Trim(" \t".ToCharArray()).ToLower();
+                if (!LanguageMapping.ContainsKey(strlan))
+                {
+                    m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Config error. Compiler is unable to recognize language type \"" + strlan + "\" specified in \"AllowedCompilers\".");
+                }
+                else
+                {
+#if DEBUG
+                    //m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Config OK. Compiler recognized language type \"" + strlan + "\" specified in \"AllowedCompilers\".");
+#endif
+                }
+                AllowedCompilers.Add(strlan, true);
+            }
+            if (AllowedCompilers.Count == 0)
+                m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Config error. Compiler could not recognize any language in \"AllowedCompilers\". Scripts will not be executed!");
+
+            // Default language
+            string defaultCompileLanguage = m_scriptEngine.ScriptConfigSource.GetString("DefaultCompileLanguage", "lsl").ToLower();
+
+            // Is this language recognized at all?
+            if (!LanguageMapping.ContainsKey(defaultCompileLanguage))
+            {
+                m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: " +
+                                            "Config error. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is not recognized as a valid language. Changing default to: \"lsl\".");
+                defaultCompileLanguage = "lsl";
+            }
+
+            // Is this language in allow-list?
+            if (!AllowedCompilers.ContainsKey(defaultCompileLanguage))
+            {
+                m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: " +
+                                            "Config error. Default language \"" + defaultCompileLanguage + "\"specified in \"DefaultCompileLanguage\" is not in list of \"AllowedCompilers\". Scripts may not be executed!");
+            }
+            else
+            {
+#if DEBUG
+//                m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: " +
+//                                            "Config OK. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is recognized as a valid language.");
+#endif
+                // LANGUAGE IS IN ALLOW-LIST
+                DefaultCompileLanguage = LanguageMapping[defaultCompileLanguage];
+            }
+
+            // We now have an allow-list, a mapping list, and a default language
+
+        }
+
+        /// <summary>
+        /// Delete old script files
+        /// </summary>
+        private void DeleteOldFiles()
+        {
+
+            // CREATE FOLDER IF IT DOESNT EXIST
+            if (!Directory.Exists(ScriptEnginesPath))
+            {
+                try
+                {
+                    Directory.CreateDirectory(ScriptEnginesPath);
+                }
+                catch (Exception ex)
+                {
+                    m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception trying to create ScriptEngine directory \"" + ScriptEnginesPath + "\": " + ex.ToString());
+                }
+            }
+
+            if (!Directory.Exists(Path.Combine(ScriptEnginesPath,
+                    m_scriptEngine.World.RegionInfo.RegionID.ToString())))
+            {
+                try
+                {
+                    Directory.CreateDirectory(Path.Combine(ScriptEnginesPath,
+                        m_scriptEngine.World.RegionInfo.RegionID.ToString()));
+                }
+                catch (Exception ex)
+                {
+                    m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception trying to create ScriptEngine directory \"" + Path.Combine(ScriptEnginesPath,
+                                            m_scriptEngine.World.RegionInfo.RegionID.ToString())+ "\": " + ex.ToString());
+                }
+            }
+
+            foreach (string file in Directory.GetFiles(Path.Combine(ScriptEnginesPath,
+                                m_scriptEngine.World.RegionInfo.RegionID.ToString())))
+            {
+                //m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: FILE FOUND: " + file);
+
+                if (file.ToLower().StartsWith(FilePrefix + "_compiled_") ||
+                    file.ToLower().StartsWith(FilePrefix + "_source_"))
+                {
+                    try
+                    {
+                        File.Delete(file);
+                    }
+                    catch (Exception ex)
+                    {
+                        m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception trying delete old script file \"" + file + "\": " + ex.ToString());
+                    }
+
+                }
+            }
+
+        }
+
+        ////private ICodeCompiler icc = codeProvider.CreateCompiler();
+        //public string CompileFromFile(string LSOFileName)
+        //{
+        //    switch (Path.GetExtension(LSOFileName).ToLower())
+        //    {
+        //        case ".txt":
+        //        case ".lsl":
+        //            Common.ScriptEngineBase.Common.SendToDebug("Source code is LSL, converting to CS");
+        //            return CompileFromLSLText(File.ReadAllText(LSOFileName));
+        //        case ".cs":
+        //            Common.ScriptEngineBase.Common.SendToDebug("Source code is CS");
+        //            return CompileFromCSText(File.ReadAllText(LSOFileName));
+        //        default:
+        //            throw new Exception("Unknown script type.");
+        //    }
+        //}
+
+        /// <summary>
+        /// Converts script from LSL to CS and calls CompileFromCSText
+        /// </summary>
+        /// <param name="Script">LSL script</param>
+        /// <returns>Filename to .dll assembly</returns>
+        public string PerformScriptCompile(string Script, string asset)
+        {
+            string OutFile = Path.Combine(ScriptEnginesPath, Path.Combine(
+                    m_scriptEngine.World.RegionInfo.RegionID.ToString(),
+                    FilePrefix + "_compiled_" + asset + ".dll"));
+//            string OutFile = Path.Combine(ScriptEnginesPath, 
+//                    FilePrefix + "_compiled_" + asset + ".dll");
+
+            if(File.Exists(OutFile))
+                return OutFile;
+
+            if (!Directory.Exists(ScriptEnginesPath))
+            {
+                try
+                {
+                    Directory.CreateDirectory(ScriptEnginesPath);
+                }
+                catch (Exception ex)
+                {
+                }
+            }
+
+            if (!Directory.Exists(Path.Combine(ScriptEnginesPath,
+                    m_scriptEngine.World.RegionInfo.RegionID.ToString())))
+            {
+                try
+                {
+                    Directory.CreateDirectory(ScriptEnginesPath);
+                }
+                catch (Exception ex)
+                {
+                }
+            }
+
+            enumCompileType l = DefaultCompileLanguage;
+
+
+            if (Script.StartsWith("//c#", true, CultureInfo.InvariantCulture))
+                l = enumCompileType.cs;
+            if (Script.StartsWith("//vb", true, CultureInfo.InvariantCulture))
+            {
+                l = enumCompileType.vb;
+                // We need to remove //vb, it won't compile with that
+
+                Script = Script.Substring(4, Script.Length - 4);
+            }
+            if (Script.StartsWith("//lsl", true, CultureInfo.InvariantCulture))
+                l = enumCompileType.lsl;
+
+            if (Script.StartsWith("//js", true, CultureInfo.InvariantCulture))
+                l = enumCompileType.js;
+
+            if (!AllowedCompilers.ContainsKey(l.ToString()))
+            {
+                // Not allowed to compile to this language!
+                string errtext = String.Empty;
+                errtext += "The compiler for language \"" + l.ToString() + "\" is not in list of allowed compilers. Script will not be executed!";
+                throw new Exception(errtext);
+            }
+
+            string compileScript = Script;
+
+            if (l == enumCompileType.lsl)
+            {
+                // Its LSL, convert it to C#
+                compileScript = LSL_Converter.Convert(Script);
+                l = enumCompileType.cs;
+            }
+
+            // Insert additional assemblies here
+
+            //ADAM: Disabled for the moment until it's working right.
+            bool enableCommanderLSL = false;
+
+            if (enableCommanderLSL == true && l == enumCompileType.cs)
+            {
+                foreach (KeyValuePair<string,
+                    ICommander> com
+                    in m_scriptEngine.World.GetCommanders())
+                {
+                    compileScript = com.Value.GenerateRuntimeAPI() + compileScript;
+                }
+            }
+
+            // End of insert
+
+
+            switch (l)
+            {
+                case enumCompileType.cs:
+                    compileScript = CreateCSCompilerScript(compileScript);
+                    break;
+                case enumCompileType.vb:
+                    compileScript = CreateVBCompilerScript(compileScript);
+                    break;
+                case enumCompileType.js:
+                    compileScript = CreateJSCompilerScript(compileScript);
+                    break;
+            }
+
+//            m_log.Debug("[ScriptEngine.DotNetEngine]: Preparing to compile the following LSL to C# translated code");
+//            m_log.Debug("");
+//            m_log.Debug(compileScript);
+
+            return CompileFromDotNetText(compileScript, l, asset);
+        }
+
+        private static string CreateJSCompilerScript(string compileScript)
+        {
+            compileScript = String.Empty +
+                "import OpenSim.Region.ScriptEngine.XEngine.Script; import System.Collections.Generic;\r\n" +
+                "package SecondLife {\r\n" +
+                "class Script extends OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass { \r\n" +
+                compileScript +
+                "} }\r\n";
+            return compileScript;
+        }
+
+        private static string CreateCSCompilerScript(string compileScript)
+        {
+
+
+            compileScript = String.Empty +
+                        "using OpenSim.Region.ScriptEngine.XEngine.Script; using System.Collections.Generic;\r\n" +
+                        String.Empty + "namespace SecondLife { " +
+                        String.Empty + "public class Script : OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass { \r\n" +
+                        @"public Script() { } " +
+                        compileScript +
+                        "} }\r\n";
+            return compileScript;
+        }
+
+        private static string CreateVBCompilerScript(string compileScript)
+        {
+            compileScript = String.Empty +
+                        "Imports OpenSim.Region.ScriptEngine.XEngine.Script: Imports System.Collections.Generic: " +
+                        String.Empty + "NameSpace SecondLife:" +
+                        String.Empty + "Public Class Script: Inherits OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass: " +
+                        "\r\nPublic Sub New()\r\nEnd Sub: " +
+                        compileScript +
+                        ":End Class :End Namespace\r\n";
+            return compileScript;
+        }
+
+        /// <summary>
+        /// Compile .NET script to .Net assembly (.dll)
+        /// </summary>
+        /// <param name="Script">CS script</param>
+        /// <returns>Filename to .dll assembly</returns>
+        internal string CompileFromDotNetText(string Script, enumCompileType lang, string asset)
+        {
+            string ext = "." + lang.ToString();
+
+            // Output assembly name
+            scriptCompileCounter++;
+            string OutFile = Path.Combine(ScriptEnginesPath, Path.Combine(
+                    m_scriptEngine.World.RegionInfo.RegionID.ToString(),
+                    FilePrefix + "_compiled_" + asset + ".dll"));
+#if DEBUG
+//            m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Starting compile of \"" + OutFile + "\".");
+#endif
+            try
+            {
+                File.Delete(OutFile);
+            }
+            catch (Exception e) // NOTLEGIT - Should be just catching FileIOException
+            {
+                //m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString());
+                throw new Exception("Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString());
+            }
+            //string OutFile = Path.Combine("ScriptEngines", "SecondLife.Script.dll");
+
+            // DEBUG - write source to disk
+            if (WriteScriptSourceToDebugFile)
+            {
+                string srcFileName = FilePrefix + "_source_" + Path.GetFileNameWithoutExtension(OutFile) + ext;
+                try
+                {
+                    File.WriteAllText(
+                        Path.Combine("ScriptEngines", srcFileName),
+                        Script);
+                }
+                catch (Exception ex) // NOTLEGIT - Should be just catching FileIOException
+                {
+                    m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception while trying to write script source to file \"" + srcFileName + "\": " + ex.ToString());
+                }
+            }
+
+            // Do actual compile
+            CompilerParameters parameters = new CompilerParameters();
+
+            parameters.IncludeDebugInformation = true;
+
+            // Add all available assemblies
+//             foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
+//             {
+//                 Console.WriteLine("Adding assembly: " + asm.Location);
+//                 parameters.ReferencedAssemblies.Add(asm.Location);
+//             }
+
+            string rootPath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
+            string rootPathSE = Path.GetDirectoryName(GetType().Assembly.Location);
+            //Console.WriteLine("Assembly location: " + rootPath);
+            parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.XEngine.Script.dll"));
+//            parameters.ReferencedAssemblies.Add(Path.Combine(rootPathSE, "OpenSim.Region.ScriptEngine.XEngine.dll"));
+
+            //parameters.ReferencedAssemblies.Add("OpenSim.Region.Environment");
+            parameters.GenerateExecutable = false;
+            parameters.OutputAssembly = OutFile;
+            parameters.IncludeDebugInformation = CompileWithDebugInformation;
+            //parameters.WarningLevel = 1; // Should be 4?
+            parameters.TreatWarningsAsErrors = false;
+
+//Console.WriteLine(Script);
+            CompilerResults results;
+            switch (lang)
+            {
+                case enumCompileType.vb:
+                    results = VBcodeProvider.CompileAssemblyFromSource(parameters, Script);
+                    break;
+                case enumCompileType.cs:
+                    results = CScodeProvider.CompileAssemblyFromSource(parameters, Script);
+                    break;
+                case enumCompileType.js:
+                    results = JScodeProvider.CompileAssemblyFromSource(parameters, Script);
+                    break;
+                default:
+                    throw new Exception("Compiler is not able to recongnize language type \"" + lang.ToString() + "\"");
+            }
+
+            // Check result
+            // Go through errors
+
+            //
+            // WARNINGS AND ERRORS
+            //
+            if (results.Errors.Count > 0)
+            {
+                string errtext = String.Empty;
+                foreach (CompilerError CompErr in results.Errors)
+                {
+                    errtext += "Line number " + (CompErr.Line - LinesToRemoveOnError) +
+                               ", Error Number: " + CompErr.ErrorNumber +
+                               ", '" + CompErr.ErrorText + "'\r\n";
+                }
+                if (!File.Exists(OutFile))
+                {
+                    throw new Exception(errtext);
+                }
+            }
+
+
+            //
+            // NO ERRORS, BUT NO COMPILED FILE
+            //
+            if (!File.Exists(OutFile))
+            {
+                string errtext = String.Empty;
+                errtext += "No compile error. But not able to locate compiled file.";
+                throw new Exception(errtext);
+            }
+            return OutFile;
+        }
+    }
+}

+ 293 - 0
OpenSim/Region/ScriptEngine/XEngine/EventManager.cs

@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using libsecondlife;
+using OpenSim.Framework;
+using OpenSim.Region.Environment.Modules.Avatar.Currency.SampleMoney;
+using OpenSim.Region.Environment.Scenes;
+using OpenSim.Region.Environment.Interfaces;
+using OpenSim.Region.ScriptEngine.XEngine.Script;
+using Axiom.Math;
+
+namespace OpenSim.Region.ScriptEngine.XEngine
+{
+    /// <summary>
+    /// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
+    /// </summary>
+    public class EventManager
+    {
+        private XEngine myScriptEngine;
+
+        public EventManager(XEngine _ScriptEngine)
+        {
+            myScriptEngine = _ScriptEngine;
+
+            myScriptEngine.Log.Info("[XEngine] Hooking up to server events");
+            myScriptEngine.World.EventManager.OnObjectGrab += touch_start;
+            myScriptEngine.World.EventManager.OnObjectDeGrab += touch_end;
+            myScriptEngine.World.EventManager.OnScriptChangedEvent += changed;
+            myScriptEngine.World.EventManager.OnScriptAtTargetEvent += at_target;
+            myScriptEngine.World.EventManager.OnScriptNotAtTargetEvent += not_at_target;
+            myScriptEngine.World.EventManager.OnScriptControlEvent += control;
+            IMoneyModule money=myScriptEngine.World.RequestModuleInterface<IMoneyModule>();
+            if (money != null)
+            {
+                money.OnObjectPaid+=HandleObjectPaid;
+            }
+        }
+
+        private void HandleObjectPaid(LLUUID objectID, LLUUID agentID,
+                int amount)
+        {
+            SceneObjectPart part =
+                    myScriptEngine.World.GetSceneObjectPart(objectID);
+
+            if (part != null)
+            {
+                money(part.LocalId, agentID, amount);
+            }
+        }
+
+        public void touch_start(uint localID, LLVector3 offsetPos,
+                IClientAPI remoteClient)
+        {
+            // Add to queue for all scripts in ObjectID object
+            XDetectParams[] det = new XDetectParams[1];
+            det[0].Key = remoteClient.AgentId;
+
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "touch_start", new Object[] { new LSL_Types.LSLInteger(1) },
+                    det));
+        }
+
+        public void touch(uint localID, LLVector3 offsetPos,
+                IClientAPI remoteClient)
+        {
+            // Add to queue for all scripts in ObjectID object
+            XDetectParams[] det = new XDetectParams[1];
+            det[0].Key = remoteClient.AgentId;
+            det[0].OffsetPos = new LSL_Types.Vector3(offsetPos.X,
+                                                     offsetPos.Y,
+                                                     offsetPos.Z);
+
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "touch", new Object[] { new LSL_Types.LSLInteger(1) },
+                    det));
+        }
+
+        public void touch_end(uint localID, IClientAPI remoteClient)
+        {
+            // Add to queue for all scripts in ObjectID object
+            XDetectParams[] det = new XDetectParams[1];
+            det[0].Key = remoteClient.AgentId;
+
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "touch_end", new Object[] { new LSL_Types.LSLInteger(1) },
+                    det));
+        }
+
+        public void changed(uint localID, uint change)
+        {
+            // Add to queue for all scripts in localID, Object pass change.
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "changed",new object[] { new LSL_Types.LSLInteger(change) },
+                    new XDetectParams[0]));
+        }
+
+        // state_entry: not processed here
+        // state_exit: not processed here
+
+        public void money(uint localID, LLUUID agentID, int amount)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "money", new object[] {
+                    new LSL_Types.LSLString(agentID.ToString()),
+                    new LSL_Types.LSLInteger(amount) },
+                    new XDetectParams[0]));
+        }
+
+        public void collision_start(uint localID, LLUUID itemID,
+                IClientAPI remoteClient)
+        {
+            // Add to queue for all scripts in ObjectID object
+            XDetectParams[] det = new XDetectParams[1];
+            det[0].Key = remoteClient.AgentId;
+
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "collision_start",
+                    new Object[] { new LSL_Types.LSLInteger(1) },
+                    det));
+        }
+
+        public void collision(uint localID, LLUUID itemID,
+                IClientAPI remoteClient)
+        {
+            // Add to queue for all scripts in ObjectID object
+            XDetectParams[] det = new XDetectParams[1];
+            det[0].Key = remoteClient.AgentId;
+
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "collision", new Object[] { new LSL_Types.LSLInteger(1) },
+                    det));
+        }
+
+        public void collision_end(uint localID, LLUUID itemID,
+                IClientAPI remoteClient)
+        {
+            // Add to queue for all scripts in ObjectID object
+            XDetectParams[] det = new XDetectParams[1];
+            det[0].Key = remoteClient.AgentId;
+
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "collision_end",
+                    new Object[] { new LSL_Types.LSLInteger(1) },
+                    det));
+        }
+
+        public void land_collision_start(uint localID, LLUUID itemID)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "land_collision_start",
+                    new object[0],
+                    new XDetectParams[0]));
+        }
+
+        public void land_collision(uint localID, LLUUID itemID)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "land_collision",
+                    new object[0],
+                    new XDetectParams[0]));
+        }
+
+        public void land_collision_end(uint localID, LLUUID itemID)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "land_collision_end",
+                    new object[0],
+                    new XDetectParams[0]));
+        }
+
+        // timer: not handled here
+        // listen: not handled here
+
+        public void on_rez(uint localID, LLUUID itemID, int startParam)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "on_rez",new object[] { 
+                    new LSL_Types.LSLInteger(startParam)},
+                    new XDetectParams[0]));
+        }
+
+        public void control(uint localID, LLUUID itemID, LLUUID agentID, uint held, uint change)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "control",new object[] { 
+                    new LSL_Types.LSLString(agentID.ToString()),
+                    new LSL_Types.LSLInteger(held),
+                    new LSL_Types.LSLInteger(change)},
+                    new XDetectParams[0]));
+        }
+
+        public void email(uint localID, LLUUID itemID, string timeSent,
+                string address, string subject, string message, int numLeft)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "email",new object[] { 
+                    new LSL_Types.LSLString(timeSent),
+                    new LSL_Types.LSLString(address),
+                    new LSL_Types.LSLString(subject),
+                    new LSL_Types.LSLString(message),
+                    new LSL_Types.LSLInteger(numLeft)},
+                    new XDetectParams[0]));
+        }
+
+        public void at_target(uint localID, uint handle, LLVector3 targetpos,
+                LLVector3 atpos)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "at_target", new object[] {
+                    new LSL_Types.LSLInteger(handle),
+                    new LSL_Types.Vector3(targetpos.X,targetpos.Y,targetpos.Z),
+                    new LSL_Types.Vector3(atpos.X,atpos.Y,atpos.Z) },
+                    new XDetectParams[0]));
+        }
+
+        public void not_at_target(uint localID)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "not_at_target",new object[0],
+                    new XDetectParams[0]));
+        }
+
+        public void at_rot_target(uint localID, LLUUID itemID)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "at_rot_target",new object[0],
+                    new XDetectParams[0]));
+        }
+
+        public void not_at_rot_target(uint localID, LLUUID itemID)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "not_at_rot_target",new object[0],
+                    new XDetectParams[0]));
+        }
+
+        // run_time_permissions: not handled here
+
+        public void attach(uint localID, LLUUID itemID, LLUUID avatar)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "attach",new object[] {
+                    new LSL_Types.LSLString(avatar.ToString()) },
+                    new XDetectParams[0]));
+        }
+
+        // dataserver: not handled here
+        // link_message: not handled here
+
+        public void moving_start(uint localID, LLUUID itemID)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "moving_start",new object[0],
+                    new XDetectParams[0]));
+        }
+
+        public void moving_end(uint localID, LLUUID itemID)
+        {
+            myScriptEngine.PostObjectEvent(localID, new XEventParams(
+                    "moving_end",new object[0],
+                    new XDetectParams[0]));
+        }
+
+        // object_rez: not handled here
+        // remote_data: not handled here
+        // http_response: not handled here
+    }
+}

+ 136 - 0
OpenSim/Region/ScriptEngine/XEngine/Executor.cs

@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using OpenSim.Region.ScriptEngine.XEngine.Script;
+
+namespace OpenSim.Region.ScriptEngine.XEngine
+{
+    public class Executor : ExecutorBase
+    {
+        // Cache functions by keeping a reference to them in a dictionary
+        private Dictionary<string, MethodInfo> Events = new Dictionary<string, MethodInfo>();
+        private Dictionary<string, scriptEvents> m_stateEvents = new Dictionary<string, scriptEvents>();
+
+        public Executor(IScript script) : base(script)
+        {
+            initEventFlags();
+        }
+
+
+        protected override scriptEvents DoGetStateEventFlags()
+        {
+            //Console.WriteLine("Get event flags for " + m_Script.State);
+
+            // Check to see if we've already computed the flags for this state
+            scriptEvents eventFlags = scriptEvents.None;
+            if (m_stateEvents.ContainsKey(m_Script.State))
+            {
+                m_stateEvents.TryGetValue(m_Script.State, out eventFlags);
+                return eventFlags;
+            }
+
+            Type type=m_Script.GetType();
+
+            // Fill in the events for this state, cache the results in the map
+            foreach (KeyValuePair<string, scriptEvents> kvp in m_eventFlagsMap)
+            {
+                string evname = m_Script.State + "_event_" + kvp.Key;
+                //Console.WriteLine("Trying event "+evname);
+                try
+                {
+                    MethodInfo mi = type.GetMethod(evname);
+                    if (mi != null)
+                    {
+                        //Console.WriteLine("Found handler for " + kvp.Key);
+                        eventFlags |= kvp.Value;
+                    }
+                }
+                catch(Exception e)
+                {
+                    //Console.WriteLine("Exeption in GetMethod:\n"+e.ToString());
+                }
+            }
+
+            // Save the flags we just computed and return the result
+            if(eventFlags != 0)
+                m_stateEvents.Add(m_Script.State, eventFlags);
+
+            //Console.WriteLine("Returning {0:x}", eventFlags);
+            return (eventFlags);
+        }
+
+        protected override void DoExecuteEvent(string FunctionName, object[] args)
+        {
+            // IMPORTANT: Types and MemberInfo-derived objects require a LOT of memory.
+            // Instead use RuntimeTypeHandle, RuntimeFieldHandle and RunTimeHandle (IntPtr) instead!
+
+            string EventName = m_Script.State + "_event_" + FunctionName;
+
+//#if DEBUG
+//            Console.WriteLine("ScriptEngine: Script event function name: " + EventName);
+//#endif
+
+            if (Events.ContainsKey(EventName) == false)
+            {
+                // Not found, create
+                Type type = m_Script.GetType();
+                try
+                {
+                    MethodInfo mi = type.GetMethod(EventName);
+                    Events.Add(EventName, mi);
+                }
+                catch
+                {
+                    Console.WriteLine("Event {0}not found", EventName);
+                    // Event name not found, cache it as not found
+                    Events.Add(EventName, null);
+                }
+            }
+
+            // Get event
+            MethodInfo ev = null;
+            Events.TryGetValue(EventName, out ev);
+
+            if (ev == null) // No event by that name!
+            {
+                //Console.WriteLine("ScriptEngine Can not find any event named: \String.Empty + EventName + "\String.Empty);
+                return;
+            }
+
+//cfk 2-7-08 dont need this right now and the default Linux build has DEBUG defined
+#if DEBUG
+            //Console.WriteLine("ScriptEngine: Executing function name: " + EventName);
+#endif
+            // Found
+            ev.Invoke(m_Script, args);
+
+        }
+    }
+}

+ 181 - 0
OpenSim/Region/ScriptEngine/XEngine/ExecutorBase.cs

@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.Remoting.Lifetime;
+using OpenSim.Region.ScriptEngine.XEngine.Script;
+
+namespace OpenSim.Region.ScriptEngine.XEngine
+{
+    public abstract class ExecutorBase : MarshalByRefObject
+    {
+        /// <summary>
+        /// Contains the script to execute functions in.
+        /// </summary>
+        protected IScript m_Script;
+
+        protected Dictionary<string, scriptEvents> m_eventFlagsMap = new Dictionary<string, scriptEvents>();
+
+        [Flags]
+        public enum scriptEvents : int
+        {
+            None = 0,
+            attach = 1,
+            collision = 15,
+            collision_end = 32,
+            collision_start = 64,
+            control = 128,
+            dataserver = 256,
+            email = 512,
+            http_response = 1024,
+            land_collision = 2048,
+            land_collision_end = 4096,
+            land_collision_start = 8192,
+            at_target = 16384,
+            listen = 32768,
+            money = 65536,
+            moving_end = 131072,
+            moving_start = 262144,
+            not_at_rot_target = 524288,
+            not_at_target = 1048576,
+            remote_data = 8388608,
+            run_time_permissions = 268435456,
+            state_entry = 1073741824,
+            state_exit = 2,
+            timer = 4,
+            touch = 8,
+            touch_end = 536870912,
+            touch_start = 2097152,
+            object_rez = 4194304
+        }
+
+        /// <summary>
+        /// Create a new instance of ExecutorBase
+        /// </summary>
+        /// <param name="Script"></param>
+        public ExecutorBase(IScript Script)
+        {
+            m_Script = Script;
+            initEventFlags();
+        }
+
+        /// <summary>
+        /// Make sure our object does not timeout when in AppDomain. (Called by ILease base class)
+        /// </summary>
+        /// <returns></returns>
+        public override Object InitializeLifetimeService()
+        {
+            //Console.WriteLine("Executor: InitializeLifetimeService()");
+            //            return null;
+            ILease lease = (ILease)base.InitializeLifetimeService();
+
+            if (lease.CurrentState == LeaseState.Initial)
+            {
+                lease.InitialLeaseTime = TimeSpan.Zero; // TimeSpan.FromMinutes(1);
+                //                lease.SponsorshipTimeout = TimeSpan.FromMinutes(2);
+                //                lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
+            }
+            return lease;
+        }
+
+        /// <summary>
+        /// Get current AppDomain
+        /// </summary>
+        /// <returns>Current AppDomain</returns>
+        public AppDomain GetAppDomain()
+        {
+            return AppDomain.CurrentDomain;
+        }
+
+        /// <summary>
+        /// Execute a specific function/event in script.
+        /// </summary>
+        /// <param name="FunctionName">Name of function to execute</param>
+        /// <param name="args">Arguments to pass to function</param>
+        public void ExecuteEvent(string FunctionName, object[] args)
+        {
+            DoExecuteEvent(FunctionName, args);
+        }
+
+        protected abstract void DoExecuteEvent(string FunctionName, object[] args);
+
+        /// <summary>
+        ///  Compute the events handled by the current state of the script
+        /// </summary>
+        /// <returns>state mask</returns>
+        public scriptEvents GetStateEventFlags()
+        {
+            return DoGetStateEventFlags();
+        }
+
+        protected abstract scriptEvents DoGetStateEventFlags();
+
+        protected void initEventFlags()
+        {
+            // Initialize the table if it hasn't already been done
+            if (m_eventFlagsMap.Count > 0)
+            {
+                return;
+            }
+
+            m_eventFlagsMap.Add("attach", scriptEvents.attach);
+            // m_eventFlagsMap.Add("at_rot_target",(long)scriptEvents.at_rot_target);
+            m_eventFlagsMap.Add("at_target", scriptEvents.at_target);
+            // m_eventFlagsMap.Add("changed",(long)scriptEvents.changed);
+            m_eventFlagsMap.Add("collision", scriptEvents.collision);
+            m_eventFlagsMap.Add("collision_end", scriptEvents.collision_end);
+            m_eventFlagsMap.Add("collision_start", scriptEvents.collision_start);
+            m_eventFlagsMap.Add("control", scriptEvents.control);
+            m_eventFlagsMap.Add("dataserver", scriptEvents.dataserver);
+            m_eventFlagsMap.Add("email", scriptEvents.email);
+            m_eventFlagsMap.Add("http_response", scriptEvents.http_response);
+            m_eventFlagsMap.Add("land_collision", scriptEvents.land_collision);
+            m_eventFlagsMap.Add("land_collision_end", scriptEvents.land_collision_end);
+            m_eventFlagsMap.Add("land_collision_start", scriptEvents.land_collision_start);
+            // m_eventFlagsMap.Add("link_message",scriptEvents.link_message);
+            m_eventFlagsMap.Add("listen", scriptEvents.listen);
+            m_eventFlagsMap.Add("money", scriptEvents.money);
+            m_eventFlagsMap.Add("moving_end", scriptEvents.moving_end);
+            m_eventFlagsMap.Add("moving_start", scriptEvents.moving_start);
+            m_eventFlagsMap.Add("not_at_rot_target", scriptEvents.not_at_rot_target);
+            m_eventFlagsMap.Add("not_at_target", scriptEvents.not_at_target);
+            // m_eventFlagsMap.Add("no_sensor",(long)scriptEvents.no_sensor);
+            // m_eventFlagsMap.Add("on_rez",(long)scriptEvents.on_rez);
+            m_eventFlagsMap.Add("remote_data", scriptEvents.remote_data);
+            m_eventFlagsMap.Add("run_time_permissions", scriptEvents.run_time_permissions);
+            // m_eventFlagsMap.Add("sensor",(long)scriptEvents.sensor);
+            m_eventFlagsMap.Add("state_entry", scriptEvents.state_entry);
+            m_eventFlagsMap.Add("state_exit", scriptEvents.state_exit);
+            m_eventFlagsMap.Add("timer", scriptEvents.timer);
+            m_eventFlagsMap.Add("touch", scriptEvents.touch);
+            m_eventFlagsMap.Add("touch_end", scriptEvents.touch_end);
+            m_eventFlagsMap.Add("touch_start", scriptEvents.touch_start);
+            m_eventFlagsMap.Add("object_rez", scriptEvents.object_rez);
+        }
+    }
+}

+ 363 - 0
OpenSim/Region/ScriptEngine/XEngine/LSL2CSConverter.cs

@@ -0,0 +1,363 @@
+/*
+* Copyright (c) Contributors, http://opensimulator.org/
+* See CONTRIBUTORS.TXT for a full list of copyright holders.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above copyright
+*       notice, this list of conditions and the following disclaimer in the
+*       documentation and/or other materials provided with the distribution.
+*     * Neither the name of the OpenSim Project nor the
+*       names of its contributors may be used to endorse or promote products
+*       derived from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS AS IS AND ANY
+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace OpenSim.Region.ScriptEngine.XEngine
+{
+    public class LSL2CSConverter
+    {
+        // Uses regex to convert LSL code to C# code.
+
+        //private Regex rnw = new Regex(@"[a-zA-Z0-9_\-]", RegexOptions.Compiled);
+        private Dictionary<string, string> dataTypes = new Dictionary<string, string>();
+        private Dictionary<string, string> quotes = new Dictionary<string, string>();
+        // c Style
+        private Regex cstylecomments = new Regex(@"/\*(.|[\r\n])*?\*/", RegexOptions.Compiled | RegexOptions.Multiline);
+        // c# one liners
+        private Regex nonCommentFwsl = new Regex("\"[a-zA-Z0-9.,:/\\n ]+//[^\"+]+([\\\\\\\"+]+)?(\\s+)?[\"+](\\s+)?(;)?", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+        private Regex conelinecomments = new Regex(@"[^:].?([\/]{2}[^\n]*)|([\n]{1,}[\/]{2}[^\n]*)", RegexOptions.Compiled | RegexOptions.Multiline);
+        // ([^\"])((?:[a-zA-Z])\.[a-zA-Z].?)([^\"])
+
+        // value we're looking for: (?:[a-zA-Z])\.[a-zA-Z]
+        public LSL2CSConverter()
+        {
+            // Only the types we need to convert
+            dataTypes.Add("void", "void");
+            dataTypes.Add("integer", "LSL_Types.LSLInteger");
+            dataTypes.Add("float", "double");
+            dataTypes.Add("string", "LSL_Types.LSLString");
+            dataTypes.Add("key", "LSL_Types.LSLString");
+            dataTypes.Add("vector", "LSL_Types.Vector3");
+            dataTypes.Add("rotation", "LSL_Types.Quaternion");
+            dataTypes.Add("list", "LSL_Types.list");
+            dataTypes.Add("null", "null");
+        }
+
+        public string Convert(string Script)
+        {
+            quotes.Clear();
+            string Return = String.Empty;
+            Script = " \r\n" + Script;
+
+            //
+            // Prepare script for processing
+            //
+
+            // Clean up linebreaks
+            Script = Regex.Replace(Script, @"\r\n", "\n");
+            Script = Regex.Replace(Script, @"\n", "\r\n");
+
+            // QUOTE REPLACEMENT
+            // temporarily replace quotes so we can work our magic on the script without
+            //  always considering if we are inside our outside quotes's
+            // TODO: Does this work on half-quotes in strings? ;)
+            string _Script = String.Empty;
+            string C;
+            bool in_quote = false;
+            bool quote_replaced = false;
+            string quote_replacement_string = "Q_U_O_T_E_REPLACEMENT_";
+            string quote = String.Empty;
+            bool last_was_escape = false;
+            int quote_replaced_count = 0;
+            
+            string removefwnoncomments = nonCommentFwsl.Replace(Script, "\"\";");
+            
+            string removecomments = conelinecomments.Replace(removefwnoncomments, "");
+            removecomments = cstylecomments.Replace(removecomments, "");
+            string[] localscript = removecomments.Split('"');
+            string checkscript = String.Empty;
+            bool flip = true;
+
+            for (int p = 0; p < localscript.Length; p++)
+            {
+                //if (localscript[p].Length >= 1)
+                //{
+                    if (!localscript[p].EndsWith(@"\"))
+                    {
+                        flip = !flip;
+                        //System.Console.WriteLine("Flip:" + flip.ToString() + " - " + localscript[p] + " ! " + localscript[p].EndsWith(@"\").ToString());
+                    }
+                //}
+                //else
+                //{
+                //    flip = !flip;
+                //    System.Console.WriteLine("Flip:" + flip.ToString() + " - " + localscript[p]);
+                //}
+                if (!flip)
+                    checkscript += localscript[p];
+            }
+
+            //System.Console.WriteLine("SCRIPT:" + checkscript);
+
+            // checks for alpha.alpha way of referring to objects in C#
+            // ignores alpha.x alpha.y, alpha.z for refering to vector components
+              Match SecurityM;
+ 
+            // BROKEN: this check is very wrong.  It block's any url in strings.
+            SecurityM = Regex.Match(checkscript, @"(?:[a-zA-Z])\.(?:[a-wA-Z]|[a-zA-Z][a-zA-Z])", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+
+            if (SecurityM.Success)
+                throw new Exception("CS0103: 'The . symbol cannot be used in LSL except in float values or vector components'.  Detected around: " + SecurityM.Captures[0].Value);
+
+            SecurityM = Regex.Match(checkscript, @"typeof\s", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+            if (SecurityM.Success)
+                throw new Exception("CS0103: 'The object.typeof method isn't allowed in LSL'");
+
+            SecurityM = Regex.Match(checkscript, @"GetType\(", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+            if (SecurityM.Success)
+                throw new Exception("CS0103: 'The object.GetType method isn't allowed in LSL'");
+
+            for (int p = 0; p < Script.Length; p++)
+            {
+                C = Script.Substring(p, 1);
+                while (true)
+                {
+                    // found " and last was not \ so this is not an escaped \"
+                    if (C == "\"" && last_was_escape == false)
+                    {
+                        // Toggle inside/outside quote
+                        in_quote = !in_quote;
+                        if (in_quote)
+                        {
+                            quote_replaced_count++;
+                        }
+                        else
+                        {
+                            if (quote == String.Empty)
+                            {
+                                // We didn't replace quote, probably because of empty string?
+                                _Script += quote_replacement_string +
+                                           quote_replaced_count.ToString().PadLeft(5, "0".ToCharArray()[0]);
+                            }
+                            // We just left a quote
+                            quotes.Add(
+                                quote_replacement_string +
+                                quote_replaced_count.ToString().PadLeft(5, "0".ToCharArray()[0]), quote);
+                            quote = String.Empty;
+                        }
+                        break;
+                    }
+
+                    if (!in_quote)
+                    {
+                        // We are not inside a quote
+                        quote_replaced = false;
+                    }
+                    else
+                    {
+                        // We are inside a quote
+                        if (!quote_replaced)
+                        {
+                            // Replace quote
+                            _Script += quote_replacement_string +
+                                       quote_replaced_count.ToString().PadLeft(5, "0".ToCharArray()[0]);
+                            quote_replaced = true;
+                        }
+                        quote += C;
+                        break;
+                    }
+                    _Script += C;
+                    break;
+                }
+                last_was_escape = false;
+                if (C == @"\")
+                {
+                    last_was_escape = true;
+                }
+            }
+            Script = _Script;
+            //
+            // END OF QUOTE REPLACEMENT
+            //
+
+            //
+            // PROCESS STATES
+            // Remove state definitions and add state names to start of each event within state
+            //
+            int ilevel = 0;
+            int lastlevel = 0;
+            string ret = String.Empty;
+            string cache = String.Empty;
+            bool in_state = false;
+            string current_statename = String.Empty;
+            for (int p = 0; p < Script.Length; p++)
+            {
+                C = Script.Substring(p, 1);
+                while (true)
+                {
+                    // inc / dec level
+                    if (C == @"{")
+                        ilevel++;
+                    if (C == @"}")
+                        ilevel--;
+                    if (ilevel < 0)
+                        ilevel = 0;
+                    cache += C;
+
+                    // if level == 0, add to return
+                    if (ilevel == 1 && lastlevel == 0)
+                    {
+                        // 0 => 1: Get last
+                        Match m =
+                          //Regex.Match(cache, @"(?![a-zA-Z_]+)\s*([a-zA-Z_]+)[^a-zA-Z_\(\)]*{",
+                            Regex.Match(cache, @"(?![a-zA-Z_]+)\s*(state\s+)?(?<statename>[a-zA-Z_][a-zA-Z_0-9]*)[^a-zA-Z_0-9\(\)]*{",
+
+                                        RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+
+                        in_state = false;
+                        if (m.Success)
+                        {
+                            // Go back to level 0, this is not a state
+                            in_state = true;
+                            current_statename = m.Groups["statename"].Captures[0].Value;
+                            //Console.WriteLine("Current statename: " + current_statename);
+                            cache =
+                                              //@"(?<s1>(?![a-zA-Z_]+)\s*)" + @"([a-zA-Z_]+)(?<s2>[^a-zA-Z_\(\)]*){",
+                                Regex.Replace(cache,
+                                              @"(?<s1>(?![a-zA-Z_]+)\s*)" + @"(state\s+)?([a-zA-Z_][a-zA-Z_0-9]*)(?<s2>[^a-zA-Z_0-9\(\)]*){",
+                                              "${s1}${s2}",
+                                              RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
+                        }
+                        ret += cache;
+                        cache = String.Empty;
+                    }
+                    if (ilevel == 0 && lastlevel == 1)
+                    {
+                        // 1 => 0: Remove last }
+                        if (in_state == true)
+                        {
+                            cache = cache.Remove(cache.Length - 1, 1);
+                            //cache = Regex.Replace(cache, "}$", String.Empty, RegexOptions.Multiline | RegexOptions.Singleline);
+
+                            //Replace function names
+                            // void dataserver(key query_id, string data) {
+                            //cache = Regex.Replace(cache, @"([^a-zA-Z_]\s*)((?!if|switch|for)[a-zA-Z_]+\s*\([^\)]*\)[^{]*{)", "$1" + "<STATE>" + "$2", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+                            //Console.WriteLine("Replacing using statename: " + current_statename);
+                            cache =
+                                Regex.Replace(cache,
+                                              @"^(\s*)((?!(if|switch|for|while)[^a-zA-Z0-9_])[a-zA-Z0-9_]*\s*\([^\)]*\)[^;]*\{)",
+                                              @"$1public " + current_statename + "_event_$2",
+                                              RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
+                        }
+
+                        ret += cache;
+                        cache = String.Empty;
+                        in_state = true;
+                        current_statename = String.Empty;
+                    }
+
+                    break;
+                }
+                lastlevel = ilevel;
+            }
+            ret += cache;
+            cache = String.Empty;
+
+            Script = ret;
+            ret = String.Empty;
+
+            foreach (string key in dataTypes.Keys)
+            {
+                string val;
+                dataTypes.TryGetValue(key, out val);
+
+                // Replace CAST - (integer) with (int)
+                Script =
+                    Regex.Replace(Script, @"\(" + key + @"\)", @"(" + val + ")",
+                                  RegexOptions.Compiled | RegexOptions.Multiline);
+                // Replace return types and function variables - integer a() and f(integer a, integer a)
+                Script =
+                    Regex.Replace(Script, @"(^|;|}|[\(,])(\s*)" + key + @"(\s+)", @"$1$2" + val + "$3",
+                                  RegexOptions.Compiled | RegexOptions.Multiline);
+                Script =
+                    Regex.Replace(Script, @"(^|;|}|[\(,])(\s*)" + key + @"(\s*)[,]", @"$1$2" + val + "$3,",
+                                  RegexOptions.Compiled | RegexOptions.Multiline);
+            }
+
+            // Add "void" in front of functions that needs it
+            Script =
+                Regex.Replace(Script,
+                              @"^(\s*public\s+)?((?!(if|switch|for)[^a-zA-Z0-9_])[a-zA-Z0-9_]*\s*\([^\)]*\)[^;]*\{)",
+                              @"$1void $2", RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+
+            // Replace <x,y,z> and <x,y,z,r>
+            Script =
+                Regex.Replace(Script, @"<([^,>;]*,[^,>;]*,[^,>;]*,[^,>;]*)>", @"new LSL_Types.Quaternion($1)",
+                              RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+            Script =
+                Regex.Replace(Script, @"<([^,>;)]*,[^,>;]*,[^,>;]*)>", @"new LSL_Types.Vector3($1)",
+                              RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+
+            // Replace List []'s
+            Script =
+                Regex.Replace(Script, @"\[([^\]]*)\]", @"new LSL_Types.list($1)",
+                              RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+
+            // Replace (string) to .ToString() //
+            Script =
+                Regex.Replace(Script, @"\(string\)\s*([a-zA-Z0-9_.]+(\s*\([^\)]*\))?)", @"$1.ToString()",
+                              RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+            Script =
+                Regex.Replace(Script, @"\((float|int)\)\s*([a-zA-Z0-9_.]+(\s*\([^\)]*\))?)", @"$1.Parse($2)",
+                              RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline);
+
+            // Replace "state STATENAME" with "state("statename")"
+            Script =
+                    Regex.Replace(Script, @"(state)\s+([^;\n\r]+)(;[\r\n\s])", "$1(\"$2\")$3",
+                  RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.Singleline | RegexOptions.IgnoreCase);
+
+            // REPLACE BACK QUOTES
+            foreach (string key in quotes.Keys)
+            {
+                string val;
+                quotes.TryGetValue(key, out val);
+                Script = Script.Replace(key, "\"" + val + "\"");
+            }
+
+            //System.Console.WriteLine(Script);
+            Return = String.Empty;// +
+                     //"using OpenSim.Region.ScriptEngine.Common; using System.Collections.Generic;";
+
+            //Return += String.Empty +
+            //          "namespace SecondLife { ";
+            //Return += String.Empty +
+            //          //"[Serializable] " +
+            //          "public class Script : OpenSim.Region.ScriptEngine.Common.LSL_BaseClass { ";
+            //Return += @"public Script() { } ";
+            Return += Script;
+            //Return += "} }\r\n";
+
+            quotes.Clear();
+
+            return Return;
+        }
+    }
+}

+ 6474 - 0
OpenSim/Region/ScriptEngine/XEngine/LSL_ScriptCommands.cs

@@ -0,0 +1,6474 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.Remoting.Lifetime;
+using System.Text;
+using System.Threading;
+using Axiom.Math;
+using libsecondlife;
+using OpenSim.Framework;
+using OpenSim.Region.Environment;
+using OpenSim.Region.Environment.Interfaces;
+using OpenSim.Region.Environment.Modules.Avatar.Currency.SampleMoney;
+using OpenSim.Region.Environment.Modules.World.Land;
+using OpenSim.Region.Environment.Scenes;
+using OpenSim.Region.ScriptEngine.XEngine;
+using OpenSim.Region.ScriptEngine.XEngine.Script;
+
+
+namespace OpenSim.Region.ScriptEngine.XEngine
+{
+    /// <summary>
+    /// Contains all LSL ll-functions. This class will be in Default AppDomain.
+    /// </summary>
+    public class LSL_ScriptCommands : MarshalByRefObject, ILSL_ScriptCommands
+    {
+        // private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+        internal XEngine m_ScriptEngine;
+        internal XScriptInstance m_Instance;
+        internal SceneObjectPart m_host;
+        internal uint m_localID;
+        internal LLUUID m_itemID;
+        internal bool throwErrorOnNotImplemented = true;
+
+        public LSL_ScriptCommands(XEngine ScriptEngine, XScriptInstance instance, SceneObjectPart host, uint localID, LLUUID itemID)
+        {
+            m_ScriptEngine = ScriptEngine;
+            m_Instance = instance;
+            m_host = host;
+            m_localID = localID;
+            m_itemID = itemID;
+
+            //m_log.Info(ScriptEngineName, "LSL_BaseClass.Start() called. Hosted by [" + m_host.Name + ":" + m_host.UUID + "@" + m_host.AbsolutePosition + "]");
+        }
+
+        private DateTime m_timer = DateTime.Now;
+        private string m_state = "default";
+        private bool m_waitingForScriptAnswer=false;
+
+
+        public string State
+        {
+            get { return m_Instance.State; }
+            set { m_Instance.State = value; }
+        }
+
+        public void state(string newState)
+        {
+            m_Instance.SetState(newState);
+        }
+
+        // Object never expires
+        public override Object InitializeLifetimeService()
+        {
+            //Console.WriteLine("LSL_BuiltIn_Commands: InitializeLifetimeService()");
+            //            return null;
+            ILease lease = (ILease)base.InitializeLifetimeService();
+
+            if (lease.CurrentState == LeaseState.Initial)
+            {
+                lease.InitialLeaseTime = TimeSpan.Zero; // TimeSpan.FromMinutes(1);
+                //                lease.SponsorshipTimeout = TimeSpan.FromMinutes(2);
+                //                lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
+            }
+            return lease;
+        }
+
+        public Scene World
+        {
+            get { return m_ScriptEngine.World; }
+        }
+
+        public void llSay(int channelID, string text)
+        {
+            m_host.AddScriptLPS(1);
+            
+            if(text.Length > 1023)
+                text=text.Substring(0, 1023);
+
+            World.SimChat(Helpers.StringToField(text),
+                          ChatTypeEnum.Say, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
+
+            IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+            wComm.DeliverMessage(ChatTypeEnum.Say, channelID, m_host.Name, m_host.UUID, text);
+        }
+
+        // Extension commands use this:
+        public ICommander GetCommander(string name)
+        {
+            return World.GetCommander(name);
+        }
+
+        private LLUUID InventorySelf()
+        {
+            LLUUID invItemID=new LLUUID();
+
+            foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
+            {
+                if (inv.Value.Type == 10 && inv.Value.ItemID == m_itemID)
+                {
+                    invItemID=inv.Key;
+                    break;
+                }
+            }
+
+            return invItemID;
+        }
+
+        private LLUUID InventoryKey(string name, int type)
+        {
+            m_host.AddScriptLPS(1);
+            foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
+            {
+                if (inv.Value.Name == name)
+                {
+                    if (inv.Value.Type != type)
+                        return LLUUID.Zero;
+
+                    return inv.Value.AssetID.ToString();
+                }
+            }
+            return LLUUID.Zero;
+        }
+
+        private LLUUID InventoryKey(string name)
+        {
+            m_host.AddScriptLPS(1);
+            foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
+            {
+                if (inv.Value.Name == name)
+                {
+                    return inv.Value.AssetID.ToString();
+                }
+            }
+            return LLUUID.Zero;
+        }
+
+        public void osSetRegionWaterHeight(double height)
+        {
+            m_host.AddScriptLPS(1);
+            //Check to make sure that the script's owner is the estate manager/master
+            //World.Permissions.GenericEstatePermission(
+            if (World.ExternalChecks.ExternalChecksCanBeGodLike(m_host.OwnerID))
+            {
+                World.EventManager.TriggerRequestChangeWaterHeight((float)height);
+            }
+        }
+
+        //These are the implementations of the various ll-functions used by the LSL scripts.
+        //starting out, we use the System.Math library for trig functions. - ckrinke 8-14-07
+        public double llSin(double f)
+        {
+            m_host.AddScriptLPS(1);
+            return (double)Math.Sin(f);
+        }
+
+        public double llCos(double f)
+        {
+            m_host.AddScriptLPS(1);
+            return (double)Math.Cos(f);
+        }
+
+        public double llTan(double f)
+        {
+            m_host.AddScriptLPS(1);
+            return (double)Math.Tan(f);
+        }
+
+        public double llAtan2(double x, double y)
+        {
+            m_host.AddScriptLPS(1);
+            return (double)Math.Atan2(y, x);
+        }
+
+        public double llSqrt(double f)
+        {
+            m_host.AddScriptLPS(1);
+            return (double)Math.Sqrt(f);
+        }
+
+        public double llPow(double fbase, double fexponent)
+        {
+            m_host.AddScriptLPS(1);
+            return (double)Math.Pow(fbase, fexponent);
+        }
+
+        public LSL_Types.LSLInteger llAbs(int i)
+        {
+            m_host.AddScriptLPS(1);
+            return (int)Math.Abs(i);
+        }
+
+        public double llFabs(double f)
+        {
+            m_host.AddScriptLPS(1);
+            return (double)Math.Abs(f);
+        }
+
+        public double llFrand(double mag)
+        {
+            m_host.AddScriptLPS(1);
+            lock (Util.RandomClass)
+            {
+                return Util.RandomClass.NextDouble() * mag;
+            }
+        }
+
+        public LSL_Types.LSLInteger llFloor(double f)
+        {
+            m_host.AddScriptLPS(1);
+            return (int)Math.Floor(f);
+        }
+
+        public LSL_Types.LSLInteger llCeil(double f)
+        {
+            m_host.AddScriptLPS(1);
+            return (int)Math.Ceiling(f);
+        }
+
+        // Xantor 01/May/2008 fixed midpointrounding (2.5 becomes 3.0 instead of 2.0, default = ToEven)
+        public LSL_Types.LSLInteger llRound(double f)
+        {
+            m_host.AddScriptLPS(1);
+            return (int)Math.Round(f, MidpointRounding.AwayFromZero);
+        }
+
+        //This next group are vector operations involving squaring and square root. ckrinke
+        public double llVecMag(LSL_Types.Vector3 v)
+        {
+            m_host.AddScriptLPS(1);
+            return LSL_Types.Vector3.Mag(v);
+        }
+
+        public LSL_Types.Vector3 llVecNorm(LSL_Types.Vector3 v)
+        {
+            m_host.AddScriptLPS(1);
+            double mag = LSL_Types.Vector3.Mag(v);
+            LSL_Types.Vector3 nor = new LSL_Types.Vector3();
+            nor.x = v.x / mag;
+            nor.y = v.y / mag;
+            nor.z = v.z / mag;
+            return nor;
+        }
+
+        public double llVecDist(LSL_Types.Vector3 a, LSL_Types.Vector3 b)
+        {
+            m_host.AddScriptLPS(1);
+            double dx = a.x - b.x;
+            double dy = a.y - b.y;
+            double dz = a.z - b.z;
+            return Math.Sqrt(dx * dx + dy * dy + dz * dz);
+        }
+
+        //Now we start getting into quaternions which means sin/cos, matrices and vectors. ckrinke
+
+        // Utility function for llRot2Euler
+
+        // normalize an angle between 0 - 2*PI (0 and 360 degrees)
+        private double NormalizeAngle(double angle)
+        {
+            angle = angle % (Math.PI * 2);
+            if (angle < 0) angle = angle + Math.PI * 2;
+            return angle;
+        }
+
+
+        // Old implementation of llRot2Euler, now normalized
+
+        public LSL_Types.Vector3 llRot2Euler(LSL_Types.Quaternion r)
+        {
+            m_host.AddScriptLPS(1);
+            //This implementation is from http://lslwiki.net/lslwiki/wakka.php?wakka=LibraryRotationFunctions. ckrinke
+            LSL_Types.Quaternion t = new LSL_Types.Quaternion(r.x * r.x, r.y * r.y, r.z * r.z, r.s * r.s);
+            double m = (t.x + t.y + t.z + t.s);
+            if (m == 0) return new LSL_Types.Vector3();
+            double n = 2 * (r.y * r.s + r.x * r.z);
+            double p = m * m - n * n;
+            if (p > 0)
+                return new LSL_Types.Vector3(NormalizeAngle(Math.Atan2(2.0 * (r.x * r.s - r.y * r.z), (-t.x - t.y + t.z + t.s))),
+                                             NormalizeAngle(Math.Atan2(n, Math.Sqrt(p))),
+                                             NormalizeAngle(Math.Atan2(2.0 * (r.z * r.s - r.x * r.y), (t.x - t.y - t.z + t.s))));
+            else if (n > 0)
+                return new LSL_Types.Vector3(0.0, Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)));
+            else
+                return new LSL_Types.Vector3(0.0, -Math.PI / 2, NormalizeAngle(Math.Atan2((r.z * r.s + r.x * r.y), 0.5 - t.x - t.z)));
+        }
+
+
+        // Xantor's newer llEuler2Rot() *try the second* inverted quaternions (-x,-y,-z,w) as LL seems to like
+        // New and improved, now actually works as described. Prim rotates as expected as does llRot2Euler.
+
+        /* From wiki:
+        The Euler angle vector (in radians) is converted to a rotation by doing the rotations around the 3 axes
+        in Z, Y, X order. So llEuler2Rot(<1.0, 2.0, 3.0> * DEG_TO_RAD) generates a rotation by taking the zero rotation,
+        a vector pointing along the X axis, first rotating it 3 degrees around the global Z axis, then rotating the resulting
+        vector 2 degrees around the global Y axis, and finally rotating that 1 degree around the global X axis.
+        */
+
+        public LSL_Types.Quaternion llEuler2Rot(LSL_Types.Vector3 v)
+        {
+            m_host.AddScriptLPS(1);
+
+            double x,y,z,s,s_i;
+
+            double cosX = Math.Cos(v.x);
+            double cosY = Math.Cos(v.y);
+            double cosZ = Math.Cos(v.z);
+            double sinX = Math.Sin(v.x);
+            double sinY = Math.Sin(v.y);
+            double sinZ = Math.Sin(v.z);
+
+            s = Math.Sqrt(cosY * cosZ - sinX * sinY * sinZ + cosX * cosZ + cosX * cosY + 1.0f) * 0.5f;
+            if (Math.Abs(s) < 0.00001) // null rotation
+            {
+                   x = 0.0f;
+                y = 1.0f;
+                z = 0.0f;
+            }
+            else
+            {
+                s_i = 1.0f / (4.0f * s);
+                x = - (-sinX * cosY - cosX * sinY * sinZ - sinX * cosZ) * s_i;
+                y = - (-cosX * sinY * cosZ + sinX * sinZ - sinY) * s_i;
+                z = - (-cosY * sinZ - sinX * sinY * cosZ - cosX * sinZ) * s_i;
+            }
+            return new LSL_Types.Quaternion(x, y, z, s);
+        }
+
+
+        public LSL_Types.Quaternion llAxes2Rot(LSL_Types.Vector3 fwd, LSL_Types.Vector3 left, LSL_Types.Vector3 up)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llAxes2Rot");
+            return new LSL_Types.Quaternion();
+        }
+
+        public LSL_Types.Vector3 llRot2Fwd(LSL_Types.Quaternion r)
+        {
+            m_host.AddScriptLPS(1);
+            return (new LSL_Types.Vector3(1,0,0) * r);
+        }
+
+        public LSL_Types.Vector3 llRot2Left(LSL_Types.Quaternion r)
+        {
+            m_host.AddScriptLPS(1);
+            return (new LSL_Types.Vector3(0, 1, 0) * r);
+        }
+
+        public LSL_Types.Vector3 llRot2Up(LSL_Types.Quaternion r)
+        {
+            m_host.AddScriptLPS(1);
+            return (new LSL_Types.Vector3(0, 0, 1) * r);
+        }
+        public LSL_Types.Quaternion llRotBetween(LSL_Types.Vector3 a, LSL_Types.Vector3 b)
+        {
+            //A and B should both be normalized
+            m_host.AddScriptLPS(1);
+            double dotProduct = LSL_Types.Vector3.Dot(a, b);
+            LSL_Types.Vector3 crossProduct = LSL_Types.Vector3.Cross(a, b);
+            double magProduct = LSL_Types.Vector3.Mag(a) * LSL_Types.Vector3.Mag(b);
+            double angle = Math.Acos(dotProduct / magProduct);
+            LSL_Types.Vector3 axis = LSL_Types.Vector3.Norm(crossProduct);
+            double s = Math.Sin(angle / 2);
+
+            return new LSL_Types.Quaternion(axis.x * s, axis.y * s, axis.z * s, (float)Math.Cos(angle / 2));
+        }
+        public void llWhisper(int channelID, string text)
+        {
+            m_host.AddScriptLPS(1);
+            
+            if(text.Length > 1023)
+                text=text.Substring(0, 1023);
+
+            World.SimChat(Helpers.StringToField(text),
+                          ChatTypeEnum.Whisper, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
+
+            IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+            wComm.DeliverMessage(ChatTypeEnum.Whisper, channelID, m_host.Name, m_host.UUID, text);
+        }
+
+        public void llShout(int channelID, string text)
+        {
+            m_host.AddScriptLPS(1);
+            
+            if(text.Length > 1023)
+                text=text.Substring(0, 1023);
+
+            World.SimChat(Helpers.StringToField(text),
+                          ChatTypeEnum.Shout, channelID, m_host.AbsolutePosition, m_host.Name, m_host.UUID, true);
+
+            IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+            wComm.DeliverMessage(ChatTypeEnum.Shout, channelID, m_host.Name, m_host.UUID, text);
+        }
+
+        public void llRegionSay(int channelID, string text)
+        {
+            if (channelID == 0)
+            {
+                LSLError("Cannot use llRegionSay() on channel 0");
+                return;
+            }
+
+            
+            if(text.Length > 1023)
+                text=text.Substring(0, 1023);
+
+            m_host.AddScriptLPS(1);
+
+            IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+            wComm.DeliverMessage(ChatTypeEnum.Region, channelID, m_host.Name, m_host.UUID, text);
+        }
+
+        public LSL_Types.LSLInteger llListen(int channelID, string name, string ID, string msg)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID keyID;
+            LLUUID.TryParse(ID, out keyID);
+            IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+            return wComm.Listen(m_localID, m_itemID, m_host.UUID, channelID, name, keyID, msg);
+        }
+
+        public void llListenControl(int number, int active)
+        {
+            m_host.AddScriptLPS(1);
+            IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+            wComm.ListenControl(m_itemID, number, active);
+        }
+
+        public void llListenRemove(int number)
+        {
+            m_host.AddScriptLPS(1);
+            IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+            wComm.ListenRemove(m_itemID, number);
+        }
+
+        public void llSensor(string name, string id, int type, double range, double arc)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID keyID = LLUUID.Zero;
+            LLUUID.TryParse(id, out keyID);
+
+            m_ScriptEngine.m_ASYNCLSLCommandManager.m_SensorRepeat.SenseOnce(m_localID, m_itemID, name, keyID, type, range, arc, m_host);
+       }
+
+        public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID keyID = LLUUID.Zero;
+            LLUUID.TryParse(id, out keyID);
+
+            m_ScriptEngine.m_ASYNCLSLCommandManager.m_SensorRepeat.SetSenseRepeatEvent(m_localID, m_itemID, name, keyID, type, range, arc, rate, m_host);
+       }
+
+        public void llSensorRemove()
+        {
+            m_host.AddScriptLPS(1);
+            m_ScriptEngine.m_ASYNCLSLCommandManager.m_SensorRepeat.UnSetSenseRepeaterEvents(m_localID, m_itemID);
+        }
+
+        public string resolveName(LLUUID objecUUID)
+        {
+            // try avatar username surname
+            UserProfileData profile = World.CommsManager.UserService.GetUserProfile(objecUUID);
+            if (profile != null)
+            {
+                string avatarname = profile.FirstName + " " + profile.SurName;
+                return avatarname;
+            }
+            // try an scene object
+            SceneObjectPart SOP = World.GetSceneObjectPart(objecUUID);
+            if (SOP != null)
+            {
+                string objectname = SOP.Name;
+                return objectname;
+            }
+
+            EntityBase SensedObject;
+            lock (World.Entities)
+            {
+                World.Entities.TryGetValue(objecUUID, out SensedObject);
+            }
+
+            if (SensedObject == null)
+                return String.Empty;
+            return SensedObject.Name;
+
+        }
+
+        public string llDetectedName(int number)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID sensedUUID = m_ScriptEngine.GetDetectID(m_itemID, number);
+            if(sensedUUID != null)
+                return resolveName(sensedUUID);
+            return String.Empty;
+       }
+
+        public LLUUID uuidDetectedKey(int number)
+        {
+            return m_ScriptEngine.GetDetectID(m_itemID, number);
+        }
+
+        public EntityBase entityDetectedKey(int number)
+        {
+            LLUUID sensedUUID = m_ScriptEngine.GetDetectID(m_itemID, number);
+            if(sensedUUID != null)
+            {
+                EntityBase SensedObject = null;
+                lock (World.Entities)
+                {
+                    World.Entities.TryGetValue(sensedUUID, out SensedObject);
+                }
+                return SensedObject;
+            }
+            return null;
+        }
+
+        public string llDetectedKey(int number)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID SensedUUID = uuidDetectedKey(number);
+            if (SensedUUID == LLUUID.Zero)
+                return String.Empty;
+
+            return SensedUUID.ToString();
+        }
+
+        public string llDetectedOwner(int number)
+        {
+            // returns UUID of owner of object detected
+            m_host.AddScriptLPS(1);
+            EntityBase SensedObject = entityDetectedKey(number);
+            if (SensedObject ==null)
+                return String.Empty;
+            LLUUID SensedUUID = uuidDetectedKey(number);
+            if (World.GetScenePresence(SensedUUID) == null)
+            {
+                // sensed object is not an avatar
+                // so get the owner of the sensed object
+                SceneObjectPart SOP = World.GetSceneObjectPart(SensedUUID);
+                if (SOP != null) { return SOP.ObjectOwner.ToString(); }
+            }
+            else
+            {
+                // sensed object is an avatar, and so must be its own owner
+                return SensedUUID.ToString();
+            }
+
+
+            return String.Empty;
+
+       }
+
+        public LSL_Types.LSLInteger llDetectedType(int number)
+        {
+            m_host.AddScriptLPS(1);
+            EntityBase SensedObject = entityDetectedKey(number);
+            if (SensedObject == null)
+                return 0;
+            int mask = 0;
+
+            LLUUID SensedUUID = uuidDetectedKey(number);
+            LSL_Types.Vector3 ZeroVector = new LSL_Types.Vector3(0, 0, 0);
+
+            if (World.GetScenePresence(SensedUUID) != null) mask |= 0x01; // actor
+            if (SensedObject.Velocity.Equals(ZeroVector))
+                mask |= 0x04; // passive non-moving
+            else
+                mask |= 0x02; // active moving
+            if (SensedObject is IScript) mask |= 0x08; // Scripted. It COULD have one hidden ...
+            return mask;
+
+        }
+
+        public LSL_Types.Vector3 llDetectedPos(int number)
+        {
+            m_host.AddScriptLPS(1);
+            EntityBase SensedObject = entityDetectedKey(number);
+            if (SensedObject == null)
+                return new LSL_Types.Vector3(0, 0, 0);
+
+            return new LSL_Types.Vector3(SensedObject.AbsolutePosition.X,SensedObject.AbsolutePosition.Y,SensedObject.AbsolutePosition.Z);
+        }
+
+        public LSL_Types.Vector3 llDetectedVel(int number)
+        {
+            m_host.AddScriptLPS(1);
+            EntityBase SensedObject = entityDetectedKey(number);
+            if (SensedObject == null)
+                return new LSL_Types.Vector3(0, 0, 0);
+
+            return new LSL_Types.Vector3(SensedObject.Velocity.X, SensedObject.Velocity.Y, SensedObject.Velocity.Z);
+           // return new LSL_Types.Vector3();
+        }
+
+        public LSL_Types.Vector3 llDetectedGrab(int number)
+        {
+            m_host.AddScriptLPS(1);
+            XDetectParams parms = m_ScriptEngine.GetDetectParams(m_itemID, number);
+
+            return parms.OffsetPos;
+        }
+
+        public LSL_Types.Quaternion llDetectedRot(int number)
+        {
+            m_host.AddScriptLPS(1);
+            EntityBase SensedObject = entityDetectedKey(number);
+            if (SensedObject == null)
+                return new LSL_Types.Quaternion();
+
+            return new LSL_Types.Quaternion(SensedObject.Rotation.x, SensedObject.Rotation.y, SensedObject.Rotation.z, SensedObject.Rotation.w);
+        }
+
+        public LSL_Types.LSLInteger llDetectedGroup(int number)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llDetectedGroup");
+            return 0;
+        }
+
+        public LSL_Types.LSLInteger llDetectedLinkNumber(int number)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llDetectedLinkNumber");
+            return 0;
+        }
+
+        public void llDie()
+        {
+            m_host.AddScriptLPS(1);
+            World.DeleteSceneObject(m_host.ParentGroup);
+        }
+
+        public double llGround(LSL_Types.Vector3 offset)
+        {
+            m_host.AddScriptLPS(1);
+            int x = (int)(m_host.AbsolutePosition.X + offset.x);
+            int y = (int)(m_host.AbsolutePosition.Y + offset.y);
+            return World.GetLandHeight(x, y);
+        }
+
+        public double llCloud(LSL_Types.Vector3 offset)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llCloud");
+            return 0;
+        }
+
+        public LSL_Types.Vector3 llWind(LSL_Types.Vector3 offset)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llWind");
+            return new LSL_Types.Vector3();
+        }
+
+        public void llSetStatus(int status, int value)
+        {
+            m_host.AddScriptLPS(1);
+
+            int statusrotationaxis = 0;
+
+            if ((status & BuiltIn_Commands_BaseClass.STATUS_PHYSICS) == BuiltIn_Commands_BaseClass.STATUS_PHYSICS)
+            {
+                if (value == 1)
+                    m_host.ScriptSetPhysicsStatus(true);
+                else
+                    m_host.ScriptSetPhysicsStatus(false);
+
+            }
+            if ((status & BuiltIn_Commands_BaseClass.STATUS_PHANTOM) == BuiltIn_Commands_BaseClass.STATUS_PHANTOM)
+            {
+                if (value == 1)
+                    m_host.ScriptSetPhantomStatus(true);
+                else
+                    m_host.ScriptSetPhantomStatus(false);
+            }
+            if ((status & BuiltIn_Commands_BaseClass.STATUS_CAST_SHADOWS) == BuiltIn_Commands_BaseClass.STATUS_CAST_SHADOWS)
+            {
+                m_host.AddFlag(LLObject.ObjectFlags.CastShadows);
+            }
+            if ((status & BuiltIn_Commands_BaseClass.STATUS_ROTATE_X) == BuiltIn_Commands_BaseClass.STATUS_ROTATE_X)
+            {
+                statusrotationaxis |= BuiltIn_Commands_BaseClass.STATUS_ROTATE_X;
+
+            }
+            if ((status & BuiltIn_Commands_BaseClass.STATUS_ROTATE_Y) == BuiltIn_Commands_BaseClass.STATUS_ROTATE_Y)
+            {
+                statusrotationaxis |= BuiltIn_Commands_BaseClass.STATUS_ROTATE_Y;
+            }
+            if ((status & BuiltIn_Commands_BaseClass.STATUS_ROTATE_Z) == BuiltIn_Commands_BaseClass.STATUS_ROTATE_Z)
+            {
+                statusrotationaxis |= BuiltIn_Commands_BaseClass.STATUS_ROTATE_Z;
+            }
+            if ((status & BuiltIn_Commands_BaseClass.STATUS_BLOCK_GRAB) == BuiltIn_Commands_BaseClass.STATUS_BLOCK_GRAB)
+            {
+                NotImplemented("llSetStatus - STATUS_BLOCK_GRAB");
+            }
+            if ((status & BuiltIn_Commands_BaseClass.STATUS_DIE_AT_EDGE) == BuiltIn_Commands_BaseClass.STATUS_DIE_AT_EDGE)
+            {
+                if (value == 1)
+                    m_host.SetDieAtEdge(true);
+                else
+                    m_host.SetDieAtEdge(false);
+            }
+            if ((status & BuiltIn_Commands_BaseClass.STATUS_RETURN_AT_EDGE) == BuiltIn_Commands_BaseClass.STATUS_RETURN_AT_EDGE)
+            {
+                NotImplemented("llSetStatus - STATUS_RETURN_AT_EDGE");
+            }
+            if ((status & BuiltIn_Commands_BaseClass.STATUS_SANDBOX) == BuiltIn_Commands_BaseClass.STATUS_SANDBOX)
+            {
+                NotImplemented("llSetStatus - STATUS_SANDBOX");
+            }
+            if (statusrotationaxis != 0)
+            {
+                m_host.SetAxisRotation(statusrotationaxis, value);
+
+            }
+        }
+
+        public LSL_Types.LSLInteger llGetStatus(int status)
+        {
+            m_host.AddScriptLPS(1);
+            // Console.WriteLine(m_host.UUID.ToString() + " status is " + m_host.GetEffectiveObjectFlags().ToString());
+            switch (status)
+            {
+                case BuiltIn_Commands_BaseClass.STATUS_PHYSICS:
+                    if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.Physics) == (uint)LLObject.ObjectFlags.Physics)
+                    {
+                        return 1;
+                    }
+                    return 0;
+                case BuiltIn_Commands_BaseClass.STATUS_PHANTOM:
+                    if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.Phantom) == (uint)LLObject.ObjectFlags.Phantom)
+                    {
+                        return 1;
+                    }
+                    return 0;
+                case BuiltIn_Commands_BaseClass.STATUS_CAST_SHADOWS:
+                    if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.CastShadows) == (uint)LLObject.ObjectFlags.CastShadows)
+                    {
+                        return 1;
+                    }
+                    return 0;
+                case BuiltIn_Commands_BaseClass.STATUS_BLOCK_GRAB:
+                    NotImplemented("llGetStatus - STATUS_BLOCK_GRAB");
+                    return 0;
+                case BuiltIn_Commands_BaseClass.STATUS_DIE_AT_EDGE:
+
+                    if (m_host.GetDieAtEdge())
+                        return 1;
+                    else
+                        return 0;
+
+                case BuiltIn_Commands_BaseClass.STATUS_RETURN_AT_EDGE:
+                    NotImplemented("llGetStatus - STATUS_RETURN_AT_EDGE");
+                    return 0;
+                case BuiltIn_Commands_BaseClass.STATUS_ROTATE_X:
+                    NotImplemented("llGetStatus - STATUS_ROTATE_X");
+                    return 0;
+                case BuiltIn_Commands_BaseClass.STATUS_ROTATE_Y:
+                    NotImplemented("llGetStatus - STATUS_ROTATE_Y");
+                    return 0;
+                case BuiltIn_Commands_BaseClass.STATUS_ROTATE_Z:
+                    NotImplemented("llGetStatus - STATUS_ROTATE_Z");
+                    return 0;
+                case BuiltIn_Commands_BaseClass.STATUS_SANDBOX:
+                    NotImplemented("llGetStatus - STATUS_SANDBOX");
+                    return 0;
+            }
+            return 0;
+        }
+
+        public void llSetScale(LSL_Types.Vector3 scale)
+        {
+            m_host.AddScriptLPS(1);
+            SetScale(m_host, scale);
+        }
+
+        private void SetScale(SceneObjectPart part, LSL_Types.Vector3 scale)
+        {
+            // TODO: this needs to trigger a persistance save as well
+            LLVector3 tmp = part.Scale;
+            tmp.X = (float)scale.x;
+            tmp.Y = (float)scale.y;
+            tmp.Z = (float)scale.z;
+            part.Scale = tmp;
+            part.SendFullUpdateToAllClients();
+        }
+
+        public LSL_Types.Vector3 llGetScale()
+        {
+            m_host.AddScriptLPS(1);
+            return new LSL_Types.Vector3(m_host.Scale.X, m_host.Scale.Y, m_host.Scale.Z);
+        }
+
+        public void llSetColor(LSL_Types.Vector3 color, int face)
+        {
+            m_host.AddScriptLPS(1);
+
+            SetColor(m_host, color, face);
+        }
+
+        private void SetColor(SceneObjectPart part, LSL_Types.Vector3 color, int face)
+        {
+            LLObject.TextureEntry tex = part.Shape.Textures;
+            LLColor texcolor;
+            if (face > -1)
+            {
+                texcolor = tex.CreateFace((uint)face).RGBA;
+                texcolor.R = (float)Math.Abs(color.x - 1);
+                texcolor.G = (float)Math.Abs(color.y - 1);
+                texcolor.B = (float)Math.Abs(color.z - 1);
+                tex.FaceTextures[face].RGBA = texcolor;
+                part.UpdateTexture(tex);
+                return;
+            }
+            else if (face == -1)
+            {
+                for (uint i = 0; i < 32; i++)
+                {
+                    if (tex.FaceTextures[i] != null)
+                    {
+                        texcolor = tex.FaceTextures[i].RGBA;
+                        texcolor.R = (float)Math.Abs(color.x - 1);
+                        texcolor.G = (float)Math.Abs(color.y - 1);
+                        texcolor.B = (float)Math.Abs(color.z - 1);
+                        tex.FaceTextures[i].RGBA = texcolor;
+                    }
+                    texcolor = tex.DefaultTexture.RGBA;
+                    texcolor.R = (float)Math.Abs(color.x - 1);
+                    texcolor.G = (float)Math.Abs(color.y - 1);
+                    texcolor.B = (float)Math.Abs(color.z - 1);
+                    tex.DefaultTexture.RGBA = texcolor;
+                }
+                part.UpdateTexture(tex);
+                return;
+            }
+        }
+
+        public double llGetAlpha(int face)
+        {
+            m_host.AddScriptLPS(1);
+            LLObject.TextureEntry tex = m_host.Shape.Textures;
+            if (face == -1) // TMP: Until we can determine number of sides, ALL_SIDES (-1) will return default color
+            {
+                return (double)((tex.DefaultTexture.RGBA.A * 255) / 255);
+            }
+            if (face > -1)
+            {
+                return (double)((tex.GetFace((uint)face).RGBA.A * 255) / 255);
+            }
+            return 0;
+        }
+
+        public void llSetAlpha(double alpha, int face)
+        {
+            m_host.AddScriptLPS(1);
+
+            SetAlpha(m_host, alpha, face);
+        }
+
+        private void SetAlpha(SceneObjectPart part, double alpha, int face)
+        {
+            LLObject.TextureEntry tex = part.Shape.Textures;
+            LLColor texcolor;
+            if (face > -1)
+            {
+                texcolor = tex.CreateFace((uint)face).RGBA;
+                texcolor.A = (float)Math.Abs(alpha - 1);
+                tex.FaceTextures[face].RGBA = texcolor;
+                part.UpdateTexture(tex);
+                return;
+            }
+            else if (face == -1)
+            {
+                for (int i = 0; i < 32; i++)
+                {
+                    if (tex.FaceTextures[i] != null)
+                    {
+                        texcolor = tex.FaceTextures[i].RGBA;
+                        texcolor.A = (float)Math.Abs(alpha - 1);
+                        tex.FaceTextures[i].RGBA = texcolor;
+                    }
+                }
+                texcolor = tex.DefaultTexture.RGBA;
+                texcolor.A = (float)Math.Abs(alpha - 1);
+                tex.DefaultTexture.RGBA = texcolor;
+                part.UpdateTexture(tex);
+                return;
+            }
+        }
+
+        public LSL_Types.Vector3 llGetColor(int face)
+        {
+            m_host.AddScriptLPS(1);
+            LLObject.TextureEntry tex = m_host.Shape.Textures;
+            LLColor texcolor;
+            LSL_Types.Vector3 rgb;
+            if (face == -1) // TMP: Until we can determine number of sides, ALL_SIDES (-1) will return default color
+            {
+                texcolor = tex.DefaultTexture.RGBA;
+                rgb.x = (255 - (texcolor.R * 255)) / 255;
+                rgb.y = (255 - (texcolor.G * 255)) / 255;
+                rgb.z = (255 - (texcolor.B * 255)) / 255;
+                return rgb;
+            }
+            if (face > -1)
+            {
+                texcolor = tex.GetFace((uint)face).RGBA;
+                rgb.x = (255 - (texcolor.R * 255)) / 255;
+                rgb.y = (255 - (texcolor.G * 255)) / 255;
+                rgb.z = (255 - (texcolor.B * 255)) / 255;
+                return rgb;
+            }
+            else
+            {
+                return new LSL_Types.Vector3();
+            }
+        }
+
+        public void llSetTexture(string texture, int face)
+        {
+            m_host.AddScriptLPS(1);
+            SetTexture(m_host, texture, face);
+        }
+
+        private void SetTexture(SceneObjectPart part, string texture, int face)
+        {
+            LLUUID textureID=new LLUUID();
+
+            if (!LLUUID.TryParse(texture, out textureID))
+            {
+                textureID=InventoryKey(texture, (int)AssetType.Texture);
+            }
+
+            if (textureID == LLUUID.Zero)
+                return;
+
+            LLObject.TextureEntry tex = part.Shape.Textures;
+
+            if (face > -1)
+            {
+                LLObject.TextureEntryFace texface = tex.CreateFace((uint)face);
+                texface.TextureID = textureID;
+                tex.FaceTextures[face] = texface;
+                part.UpdateTexture(tex);
+                return;
+            }
+            else if (face == -1)
+            {
+                for (uint i = 0; i < 32; i++)
+                {
+                    if (tex.FaceTextures[i] != null)
+                    {
+                        tex.FaceTextures[i].TextureID = textureID;
+                    }
+                }
+                tex.DefaultTexture.TextureID = textureID;
+                part.UpdateTexture(tex);
+                return;
+            }
+        }
+
+        public void llScaleTexture(double u, double v, int face)
+        {
+            m_host.AddScriptLPS(1);
+
+            ScaleTexture(m_host, u, v, face);
+        }
+
+        private void ScaleTexture(SceneObjectPart part, double u, double v, int face)
+        {
+            LLObject.TextureEntry tex = part.Shape.Textures;
+            if (face > -1)
+            {
+                LLObject.TextureEntryFace texface = tex.CreateFace((uint)face);
+                texface.RepeatU = (float)u;
+                texface.RepeatV = (float)v;
+                tex.FaceTextures[face] = texface;
+                part.UpdateTexture(tex);
+                return;
+            }
+            if (face == -1)
+            {
+                for (int i = 0; i < 32; i++)
+                {
+                    if (tex.FaceTextures[i] != null)
+                    {
+                        tex.FaceTextures[i].RepeatU = (float)u;
+                        tex.FaceTextures[i].RepeatV = (float)v;
+                    }
+                }
+                tex.DefaultTexture.RepeatU = (float)u;
+                tex.DefaultTexture.RepeatV = (float)v;
+                part.UpdateTexture(tex);
+                return;
+            }
+        }
+
+        public void llOffsetTexture(double u, double v, int face)
+        {
+            m_host.AddScriptLPS(1);
+            OffsetTexture(m_host, u, v, face);
+        }
+
+        private void OffsetTexture(SceneObjectPart part, double u, double v, int face)
+        {
+            LLObject.TextureEntry tex = part.Shape.Textures;
+            if (face > -1)
+            {
+                LLObject.TextureEntryFace texface = tex.CreateFace((uint)face);
+                texface.OffsetU = (float)u;
+                texface.OffsetV = (float)v;
+                tex.FaceTextures[face] = texface;
+                part.UpdateTexture(tex);
+                return;
+            }
+            if (face == -1)
+            {
+                for (int i = 0; i < 32; i++)
+                {
+                    if (tex.FaceTextures[i] != null)
+                    {
+                        tex.FaceTextures[i].OffsetU = (float)u;
+                        tex.FaceTextures[i].OffsetV = (float)v;
+                    }
+                }
+                tex.DefaultTexture.OffsetU = (float)u;
+                tex.DefaultTexture.OffsetV = (float)v;
+                part.UpdateTexture(tex);
+                return;
+            }
+        }
+
+        public void llRotateTexture(double rotation, int face)
+        {
+            m_host.AddScriptLPS(1);
+            RotateTexture(m_host, rotation, face);
+        }
+
+        private void RotateTexture(SceneObjectPart part, double rotation, int face)
+        {
+            LLObject.TextureEntry tex = part.Shape.Textures;
+            if (face > -1)
+            {
+                LLObject.TextureEntryFace texface = tex.CreateFace((uint)face);
+                texface.Rotation = (float)rotation;
+                tex.FaceTextures[face] = texface;
+                part.UpdateTexture(tex);
+                return;
+            }
+            if (face == -1)
+            {
+                for (int i = 0; i < 32; i++)
+                {
+                    if (tex.FaceTextures[i] != null)
+                    {
+                        tex.FaceTextures[i].Rotation = (float)rotation;
+                    }
+                }
+                tex.DefaultTexture.Rotation = (float)rotation;
+                part.UpdateTexture(tex);
+                return;
+            }
+        }
+
+        public string llGetTexture(int face)
+        {
+            m_host.AddScriptLPS(1);
+            LLObject.TextureEntry tex = m_host.Shape.Textures;
+            if (face == -1)
+            {
+                face = 0;
+            }
+            if (face > -1)
+            {
+                LLObject.TextureEntryFace texface;
+                texface = tex.GetFace((uint)face);
+                return texface.TextureID.ToString();
+            }
+            else
+            {
+                return String.Empty;
+            }
+        }
+
+        public void llSetPos(LSL_Types.Vector3 pos)
+        {
+            m_host.AddScriptLPS(1);
+
+            SetPos(m_host, pos);
+        }
+
+        private void SetPos(SceneObjectPart part, LSL_Types.Vector3 pos)
+        {
+            if (part.ParentID != 0)
+            {
+                part.UpdateOffSet(new LLVector3((float)pos.x, (float)pos.y, (float)pos.z));
+            }
+            else
+            {
+                part.UpdateGroupPosition(new LLVector3((float)pos.x, (float)pos.y, (float)pos.z));
+            }
+        }
+
+        public LSL_Types.Vector3 llGetPos()
+        {
+            m_host.AddScriptLPS(1);
+            return new LSL_Types.Vector3(m_host.AbsolutePosition.X,
+                                         m_host.AbsolutePosition.Y,
+                                         m_host.AbsolutePosition.Z);
+        }
+
+        public LSL_Types.Vector3 llGetLocalPos()
+        {
+            m_host.AddScriptLPS(1);
+            if (m_host.ParentID != 0)
+            {
+                return new LSL_Types.Vector3(m_host.OffsetPosition.X,
+                                             m_host.OffsetPosition.Y,
+                                             m_host.OffsetPosition.Z);
+            }
+            else
+            {
+                return new LSL_Types.Vector3(m_host.AbsolutePosition.X,
+                                             m_host.AbsolutePosition.Y,
+                                             m_host.AbsolutePosition.Z);
+            }
+        }
+
+        public void llSetRot(LSL_Types.Quaternion rot)
+        {
+            m_host.AddScriptLPS(1);
+
+            SetRot(m_host, rot);
+        }
+
+        private void SetRot(SceneObjectPart part, LSL_Types.Quaternion rot)
+        {
+            part.UpdateRotation(new LLQuaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s));
+            // Update rotation does not move the object in the physics scene if it's a linkset.
+            part.ParentGroup.AbsolutePosition = part.ParentGroup.AbsolutePosition;
+        }
+
+        public LSL_Types.Quaternion llGetRot()
+        {
+            m_host.AddScriptLPS(1);
+            LLQuaternion q = m_host.RotationOffset;
+            return new LSL_Types.Quaternion(q.X, q.Y, q.Z, q.W);
+        }
+
+        public LSL_Types.Quaternion llGetLocalRot()
+        {
+            m_host.AddScriptLPS(1);
+            return new LSL_Types.Quaternion(m_host.RotationOffset.X, m_host.RotationOffset.Y, m_host.RotationOffset.Z, m_host.RotationOffset.W);
+        }
+
+        public void llSetForce(LSL_Types.Vector3 force, int local)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetForce");
+        }
+
+        public LSL_Types.Vector3 llGetForce()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetForce");
+            return new LSL_Types.Vector3();
+        }
+
+        public LSL_Types.LSLInteger llTarget(LSL_Types.Vector3 position, double range)
+        {
+            m_host.AddScriptLPS(1);
+            return m_host.registerTargetWaypoint(new LLVector3((float)position.x, (float)position.y, (float)position.z), (float)range);
+
+        }
+
+        public void llTargetRemove(int number)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.unregisterTargetWaypoint(number);
+        }
+
+        public LSL_Types.LSLInteger llRotTarget(LSL_Types.Quaternion rot, double error)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llRotTarget");
+            return 0;
+        }
+
+        public void llRotTargetRemove(int number)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llRotTargetRemove");
+        }
+
+        public void llMoveToTarget(LSL_Types.Vector3 target, double tau)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.MoveToTarget(new LLVector3((float)target.x, (float)target.y, (float)target.z), (float)tau);
+        }
+
+        public void llStopMoveToTarget()
+        {
+            m_host.AddScriptLPS(1);
+            m_host.StopMoveToTarget();
+        }
+
+        public void llApplyImpulse(LSL_Types.Vector3 force, int local)
+        {
+            m_host.AddScriptLPS(1);
+            //No energy force yet
+
+            if (force.x > 20000)
+                    force.x = 20000;
+            if (force.y > 20000)
+                    force.y = 20000;
+            if (force.z > 20000)
+                    force.z = 20000;
+
+            if (local == 1)
+            {
+                m_host.ApplyImpulse(new LLVector3((float)force.x, (float)force.y, (float)force.z), true);
+            }
+            else
+            {
+
+                m_host.ApplyImpulse(new LLVector3((float)force.x,(float)force.y,(float)force.z), false);
+            }
+        }
+
+        public void llApplyRotationalImpulse(LSL_Types.Vector3 force, int local)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llApplyRotationalImpulse");
+        }
+
+        public void llSetTorque(LSL_Types.Vector3 torque, int local)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetTorque");
+        }
+
+        public LSL_Types.Vector3 llGetTorque()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetTorque");
+            return new LSL_Types.Vector3();
+        }
+
+        public void llSetForceAndTorque(LSL_Types.Vector3 force, LSL_Types.Vector3 torque, int local)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetForceAndTorque");
+        }
+
+        public LSL_Types.Vector3 llGetVel()
+        {
+            m_host.AddScriptLPS(1);
+            return new LSL_Types.Vector3(m_host.Velocity.X, m_host.Velocity.Y, m_host.Velocity.Z);
+        }
+
+        public LSL_Types.Vector3 llGetAccel()
+        {
+            m_host.AddScriptLPS(1);
+            return new LSL_Types.Vector3(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z);
+        }
+
+        public LSL_Types.Vector3 llGetOmega()
+        {
+            m_host.AddScriptLPS(1);
+            return new LSL_Types.Vector3(m_host.RotationalVelocity.X, m_host.RotationalVelocity.Y, m_host.RotationalVelocity.Z);
+        }
+
+        public double llGetTimeOfDay()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetTimeOfDay");
+            return 0;
+        }
+
+        public double llGetWallclock()
+        {
+            m_host.AddScriptLPS(1);
+            return DateTime.Now.TimeOfDay.TotalSeconds;
+        }
+
+        public double llGetTime()
+        {
+            m_host.AddScriptLPS(1);
+            TimeSpan ScriptTime = DateTime.Now - m_timer;
+            return (double)((ScriptTime.TotalMilliseconds / 1000)*World.TimeDilation);
+        }
+
+        public void llResetTime()
+        {
+            m_host.AddScriptLPS(1);
+            m_timer = DateTime.Now;
+        }
+
+        public double llGetAndResetTime()
+        {
+            m_host.AddScriptLPS(1);
+            TimeSpan ScriptTime = DateTime.Now - m_timer;
+            m_timer = DateTime.Now;
+            return (double)((ScriptTime.TotalMilliseconds / 1000)*World.TimeDilation);
+        }
+
+        public void llSound()
+        {
+            m_host.AddScriptLPS(1);
+            // This function has been deprecated
+            // see http://www.lslwiki.net/lslwiki/wakka.php?wakka=llSound
+            Deprecated("llSound");
+        }
+
+        public void llPlaySound(string sound, double volume)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.SendSound(sound, volume, false, 0);
+        }
+
+        public void llLoopSound(string sound, double volume)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.SendSound(sound, volume, false, 1);
+        }
+
+        public void llLoopSoundMaster(string sound, double volume)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llLoopSoundMaster");
+        }
+
+        public void llLoopSoundSlave(string sound, double volume)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llLoopSoundSlave");
+        }
+
+        public void llPlaySoundSlave(string sound, double volume)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llPlaySoundSlave");
+        }
+
+        public void llTriggerSound(string sound, double volume)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.SendSound(sound, volume, true, 0);
+        }
+
+        public void llStopSound()
+        {
+            m_host.AddScriptLPS(1);
+            m_host.SendSound(LLUUID.Zero.ToString(), 1.0, false, 2);
+        }
+
+        public void llPreloadSound(string sound)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.PreloadSound(sound);
+        }
+
+        /// <summary>
+        /// Return a portion of the designated string bounded by
+        /// inclusive indices (start and end). As usual, the negative
+        /// indices, and the tolerance for out-of-bound values, makes
+        /// this more complicated than it might otherwise seem.
+        /// </summary>
+
+        public string llGetSubString(string src, int start, int end)
+        {
+
+            m_host.AddScriptLPS(1);
+
+            // Normalize indices (if negative).
+            // After normlaization they may still be
+            // negative, but that is now relative to
+            // the start, rather than the end, of the
+            // sequence.
+
+            if (start < 0)
+            {
+                start = src.Length+start;
+            }
+            if (end < 0)
+            {
+                end = src.Length+end;
+            }
+
+            // Conventional substring
+            if (start <= end)
+            {
+                // Implies both bounds are out-of-range.
+                if (end < 0 || start >= src.Length)
+                {
+                    return String.Empty;
+                }
+                // If end is positive, then it directly
+                // corresponds to the lengt of the substring
+                // needed (plus one of course). BUT, it
+                // must be within bounds.
+                if (end >= src.Length)
+                {
+                    end = src.Length-1;
+                }
+
+                if (start < 0)
+                {
+                    return src.Substring(0,end+1);
+                }
+                // Both indices are positive
+                return src.Substring(start, (end+1) - start);
+            }
+
+            // Inverted substring (end < start)
+            else
+            {
+                // Implies both indices are below the
+                // lower bound. In the inverted case, that
+                // means the entire string will be returned
+                // unchanged.
+                if (start < 0)
+                {
+                    return src;
+                }
+                // If both indices are greater than the upper
+                // bound the result may seem initially counter
+                // intuitive.
+                if (end >= src.Length)
+                {
+                    return src;
+                }
+
+                if (end < 0)
+                {
+                    if (start < src.Length)
+                    {
+                        return src.Substring(start);
+                    }
+                    else
+                    {
+                        return String.Empty;
+                    }
+                }
+                else
+                {
+                    if (start < src.Length)
+                    {
+                        return src.Substring(0,end+1) + src.Substring(start);
+                    }
+                    else
+                    {
+                        return src.Substring(0,end+1);
+                    }
+                }
+            }
+         }
+
+        /// <summary>
+        /// Delete substring removes the specified substring bounded
+        /// by the inclusive indices start and end. Indices may be
+        /// negative (indicating end-relative) and may be inverted,
+        /// i.e. end < start.
+        /// </summary>
+
+        public string llDeleteSubString(string src, int start, int end)
+        {
+
+            m_host.AddScriptLPS(1);
+
+            // Normalize indices (if negative).
+            // After normlaization they may still be
+            // negative, but that is now relative to
+            // the start, rather than the end, of the
+            // sequence.
+            if (start < 0)
+            {
+                start = src.Length+start;
+            }
+            if (end < 0)
+            {
+                end = src.Length+end;
+            }
+            // Conventionally delimited substring
+            if (start <= end)
+            {
+                // If both bounds are outside of the existing
+                // string, then return unchanges.
+                if (end < 0 || start >= src.Length)
+                {
+                    return src;
+                }
+                // At least one bound is in-range, so we
+                // need to clip the out-of-bound argument.
+                if (start < 0)
+                {
+                    start = 0;
+                }
+
+                if (end >= src.Length)
+                {
+                    end = src.Length-1;
+                }
+
+                return src.Remove(start,end-start+1);
+            }
+            // Inverted substring
+            else
+            {
+                // In this case, out of bounds means that
+                // the existing string is part of the cut.
+                if (start < 0 || end >= src.Length)
+                {
+                    return String.Empty;
+                }
+
+                if (end > 0)
+                {
+                    if (start < src.Length)
+                    {
+                        return src.Remove(start).Remove(0,end+1);
+                    }
+                    else
+                    {
+                        return src.Remove(0,end+1);
+                    }
+                }
+                else
+                {
+                    if (start < src.Length)
+                    {
+                        return src.Remove(start);
+                    }
+                    else
+                    {
+                        return src;
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Insert string inserts the specified string identified by src
+        /// at the index indicated by index. Index may be negative, in
+        /// which case it is end-relative. The index may exceed either
+        /// string bound, with the result being a concatenation.
+        /// </summary>
+
+        public string llInsertString(string dest, int index, string src)
+        {
+
+            m_host.AddScriptLPS(1);
+
+            // Normalize indices (if negative).
+            // After normlaization they may still be
+            // negative, but that is now relative to
+            // the start, rather than the end, of the
+            // sequence.
+            if (index < 0)
+            {
+                index = dest.Length+index;
+
+                // Negative now means it is less than the lower
+                // bound of the string.
+
+                if (index < 0)
+                {
+                    return src+dest;
+                }
+
+            }
+
+            if (index >= dest.Length)
+            {
+                return dest+src;
+            }
+
+            // The index is in bounds.
+            // In this case the index refers to the index that will
+            // be assigned to the first character of the inserted string.
+            // So unlike the other string operations, we do not add one
+            // to get the correct string length.
+            return dest.Substring(0,index)+src+dest.Substring(index);
+
+        }
+
+        public string llToUpper(string src)
+        {
+            m_host.AddScriptLPS(1);
+            return src.ToUpper();
+        }
+
+        public string llToLower(string src)
+        {
+            m_host.AddScriptLPS(1);
+            return src.ToLower();
+        }
+
+        public LSL_Types.LSLInteger llGiveMoney(string destination, int amount)
+        {
+            LLUUID invItemID=InventorySelf();
+            if (invItemID == LLUUID.Zero)
+                return 0;
+
+            m_host.AddScriptLPS(1);
+
+            if (m_host.TaskInventory[invItemID].PermsGranter == LLUUID.Zero)
+                return 0;
+
+            if ((m_host.TaskInventory[invItemID].PermsMask & BuiltIn_Commands_BaseClass.PERMISSION_DEBIT) == 0)
+            {
+                LSLError("No permissions to give money");
+                return 0;
+            }
+
+            LLUUID toID=new LLUUID();
+
+            if (!LLUUID.TryParse(destination, out toID))
+            {
+                LSLError("Bad key in llGiveMoney");
+                return 0;
+            }
+
+            IMoneyModule money=World.RequestModuleInterface<IMoneyModule>();
+
+            if (money == null)
+            {
+                NotImplemented("llGiveMoney");
+                return 0;
+            }
+
+            bool result=money.ObjectGiveMoney(m_host.ParentGroup.RootPart.UUID, m_host.ParentGroup.RootPart.OwnerID, toID, amount);
+
+            if (result)
+                return 1;
+
+            return 0;
+        }
+
+        public void llMakeExplosion()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llMakeExplosion");
+        }
+
+        public void llMakeFountain()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llMakeFountain");
+        }
+
+        public void llMakeSmoke()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llMakeSmoke");
+        }
+
+        public void llMakeFire()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llMakeFire");
+        }
+
+        public void llRezObject(string inventory, LSL_Types.Vector3 pos, LSL_Types.Vector3 vel, LSL_Types.Quaternion rot, int param)
+        {
+            m_host.AddScriptLPS(1);
+            //NotImplemented("llRezObject");
+            bool found = false;
+
+            // Instead of using return;, I'm using continue; because in our TaskInventory implementation
+            // it's possible to have two items with the same task inventory name.
+            // this is an easter egg of sorts.
+
+            foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
+            {
+                if (inv.Value.Name == inventory)
+                {
+                    // make sure we're an object.
+                    if (inv.Value.InvType != (int)InventoryType.Object)
+                    {
+                        llSay(0, "Unable to create requested object. Object is missing from database.");
+                        continue;
+                    }
+
+                    LLVector3 llpos = new LLVector3((float)pos.x, (float)pos.y, (float)pos.z);
+
+                    // test if we're further away then 10m
+                    if (Util.GetDistanceTo(llpos, m_host.AbsolutePosition) > 10)
+                        return; // wiki says, if it's further away then 10m, silently fail.
+
+                    LLVector3 llvel = new LLVector3((float)vel.x, (float)vel.y, (float)vel.z);
+
+                    // need the magnitude later
+                    float velmag = (float)Util.GetMagnitude(llvel);
+
+                    SceneObjectGroup new_group = World.RezObject(inv.Value, llpos, new LLQuaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s), llvel, param);
+
+                    // If either of these are null, then there was an unknown error.
+                    if (new_group == null)
+                        continue;
+                    if (new_group.RootPart == null)
+                        continue;
+
+                    // objects rezzed with this method are die_at_edge by default.
+                    new_group.RootPart.SetDieAtEdge(true);
+
+                    m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
+                            "object_rez", new Object[] {
+                            new LSL_Types.LSLString(
+                            new_group.RootPart.UUID.ToString()) },
+                            new XDetectParams[0]));
+
+                    float groupmass = new_group.GetMass();
+
+                    //Recoil.
+                    llApplyImpulse(new LSL_Types.Vector3(llvel.X * groupmass, llvel.Y * groupmass, llvel.Z * groupmass), 0);
+                    found = true;
+                    //script delay
+                    System.Threading.Thread.Sleep((int)((groupmass * velmag) / 10));
+                    break;
+                }
+            }
+            if (!found)
+                llSay(0, "Could not find object " + inventory);
+        }
+
+        public void llLookAt(LSL_Types.Vector3 target, double strength, double damping)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llLookAt");
+        }
+
+        public void llStopLookAt()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llStopLookAt");
+        }
+
+        public void llSetTimerEvent(double sec)
+        {
+            m_host.AddScriptLPS(1);
+            // Setting timer repeat
+            m_ScriptEngine.m_ASYNCLSLCommandManager.m_Timer.SetTimerEvent(m_localID, m_itemID, sec);
+        }
+
+        public void llSleep(double sec)
+        {
+            m_host.AddScriptLPS(1);
+            Thread.Sleep((int)(sec * 1000));
+        }
+
+        public double llGetMass()
+        {
+            m_host.AddScriptLPS(1);
+            return m_host.GetMass();
+        }
+
+        public void llCollisionFilter(string name, string id, int accept)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llCollisionFilter");
+        }
+
+        public void llTakeControls(int controls, int accept, int pass_on)
+        {
+            if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
+            {
+                return;
+            }
+
+            if (m_host.TaskInventory[InventorySelf()].PermsGranter != LLUUID.Zero)
+            {
+                ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[InventorySelf()].PermsGranter);
+
+                if (presence != null)
+                {
+                    if ((m_host.TaskInventory[InventorySelf()].PermsMask & BuiltIn_Commands_BaseClass.PERMISSION_TAKE_CONTROLS) != 0)
+                    {
+                        presence.RegisterControlEventsToScript(controls, accept, pass_on, m_localID, m_itemID);
+
+                    }
+                }
+            }
+
+            m_host.AddScriptLPS(1);
+            //NotImplemented("llTakeControls");
+        }
+
+        public void llReleaseControls()
+        {
+            m_host.AddScriptLPS(1);
+
+            if (!m_host.TaskInventory.ContainsKey(InventorySelf()))
+            {
+                return;
+            }
+
+            if (m_host.TaskInventory[InventorySelf()].PermsGranter != LLUUID.Zero)
+            {
+                ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[InventorySelf()].PermsGranter);
+
+                if (presence != null)
+                {
+                    if ((m_host.TaskInventory[InventorySelf()].PermsMask & BuiltIn_Commands_BaseClass.PERMISSION_TAKE_CONTROLS) != 0)
+                    {
+                        // Unregister controls from Presence
+                        presence.UnRegisterControlEventsToScript(m_localID, m_itemID);
+                        // Remove Take Control permission.
+                        m_host.TaskInventory[InventorySelf()].PermsMask &= ~BuiltIn_Commands_BaseClass.PERMISSION_TAKE_CONTROLS;
+                    }
+                }
+            }
+        }
+
+        public void llAttachToAvatar(int attachment)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llAttachToAvatar");
+        }
+
+        public void llDetachFromAvatar()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llDetachFromAvatar");
+        }
+
+        public void llTakeCamera()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llTakeCamera");
+        }
+
+        public void llReleaseCamera()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llReleaseCamera");
+        }
+
+        public string llGetOwner()
+        {
+            m_host.AddScriptLPS(1);
+
+            return m_host.ObjectOwner.ToString();
+        }
+
+        public void llInstantMessage(string user, string message)
+        {
+            m_host.AddScriptLPS(1);
+
+            // We may be able to use ClientView.SendInstantMessage here, but we need a client instance.
+            // InstantMessageModule.OnInstantMessage searches through a list of scenes for a client matching the toAgent,
+            // but I don't think we have a list of scenes available from here.
+            // (We also don't want to duplicate the code in OnInstantMessage if we can avoid it.)
+
+            // user is a UUID
+
+            // TODO: figure out values for client, fromSession, and imSessionID
+            // client.SendInstantMessage(m_host.UUID, fromSession, message, user, imSessionID, m_host.Name, AgentManager.InstantMessageDialog.MessageFromAgent, (uint)Util.UnixTimeSinceEpoch());
+            LLUUID friendTransactionID = LLUUID.Random();
+
+            //m_pendingFriendRequests.Add(friendTransactionID, fromAgentID);
+
+            GridInstantMessage msg = new GridInstantMessage();
+            msg.fromAgentID = new Guid(m_host.UUID.ToString()); // fromAgentID.UUID;
+            msg.fromAgentSession = new Guid(friendTransactionID.ToString());// fromAgentSession.UUID;
+            msg.toAgentID = new Guid(user); // toAgentID.UUID;
+            msg.imSessionID = new Guid(friendTransactionID.ToString()); // This is the item we're mucking with here
+            Console.WriteLine("[Scripting IM]: From:" + msg.fromAgentID.ToString() + " To: " + msg.toAgentID.ToString() + " Session:" + msg.imSessionID.ToString() + " Message:" + message);
+            Console.WriteLine("[Scripting IM]: Filling Session: " + msg.imSessionID.ToString());
+            msg.timestamp = (uint)Util.UnixTimeSinceEpoch();// timestamp;
+            //if (client != null)
+            //{
+                msg.fromAgentName = m_host.Name;//client.FirstName + " " + client.LastName;// fromAgentName;
+            //}
+            //else
+            //{
+            //    msg.fromAgentName = "(hippos)";// Added for posterity.  This means that we can't figure out who sent it
+            //}
+            msg.message = message;
+            msg.dialog = (byte)19; // messgage from script ??? // dialog;
+            msg.fromGroup = false;// fromGroup;
+            msg.offline = (byte)0; //offline;
+            msg.ParentEstateID = 0; //ParentEstateID;
+            msg.Position = new sLLVector3();// new sLLVector3(m_host.AbsolutePosition);
+            msg.RegionID = World.RegionInfo.RegionID.UUID;//RegionID.UUID;
+            msg.binaryBucket = new byte[0];// binaryBucket;
+            World.TriggerGridInstantMessage(msg, InstantMessageReceiver.IMModule);
+            //  NotImplemented("llInstantMessage");
+      }
+
+        public void llEmail(string address, string subject, string message)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llEmail");
+        }
+
+        public void llGetNextEmail(string address, string subject)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetNextEmail");
+        }
+
+        public string llGetKey()
+        {
+            m_host.AddScriptLPS(1);
+            return m_host.UUID.ToString();
+        }
+
+        public void llSetBuoyancy(double buoyancy)
+        {
+            m_host.AddScriptLPS(1);
+            if (m_host.ParentGroup != null)
+            {
+                if (m_host.ParentGroup.RootPart != null)
+                {
+                    m_host.ParentGroup.RootPart.SetBuoyancy((float)buoyancy);
+                }
+            }
+        }
+
+
+
+        public void llSetHoverHeight(double height, int water, double tau)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetHoverHeight");
+        }
+
+        public void llStopHover()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llStopHover");
+        }
+
+        public void llMinEventDelay(double delay)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llMinEventDelay");
+        }
+
+        public void llSoundPreload()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSoundPreload");
+        }
+
+        public void llRotLookAt(LSL_Types.Quaternion target, double strength, double damping)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llRotLookAt");
+        }
+
+        public LSL_Types.LSLInteger llStringLength(string str)
+        {
+            m_host.AddScriptLPS(1);
+            if (str.Length > 0)
+            {
+                return str.Length;
+            }
+            else
+            {
+                return 0;
+            }
+        }
+
+        public void llStartAnimation(string anim)
+        {
+            m_host.AddScriptLPS(1);
+
+            LLUUID invItemID=InventorySelf();
+            if (invItemID == LLUUID.Zero)
+                return;
+
+            if (m_host.TaskInventory[invItemID].PermsGranter == LLUUID.Zero)
+                return;
+
+            if ((m_host.TaskInventory[invItemID].PermsMask & BuiltIn_Commands_BaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
+            {
+                ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter);
+
+                if (presence != null)
+                {
+                    // Do NOT try to parse LLUUID, animations cannot be triggered by ID
+                    LLUUID animID=InventoryKey(anim, (int)AssetType.Animation);
+                    if (animID == LLUUID.Zero)
+                        presence.AddAnimation(anim);
+                    else
+                        presence.AddAnimation(animID);
+                }
+            }
+        }
+
+        public void llStopAnimation(string anim)
+        {
+            m_host.AddScriptLPS(1);
+
+            LLUUID invItemID=InventorySelf();
+            if (invItemID == LLUUID.Zero)
+                return;
+
+            if (m_host.TaskInventory[invItemID].PermsGranter == LLUUID.Zero)
+                return;
+
+            if ((m_host.TaskInventory[invItemID].PermsMask & BuiltIn_Commands_BaseClass.PERMISSION_TRIGGER_ANIMATION) != 0)
+            {
+                LLUUID animID = new LLUUID();
+
+                if (!LLUUID.TryParse(anim, out animID))
+                {
+                    animID=InventoryKey(anim);
+                }
+
+                if (animID == LLUUID.Zero)
+                    return;
+
+                ScenePresence presence = World.GetScenePresence(m_host.TaskInventory[invItemID].PermsGranter);
+
+                if (presence != null)
+                {
+                    if (animID == LLUUID.Zero)
+                        presence.RemoveAnimation(anim);
+                    else
+                        presence.RemoveAnimation(animID);
+                }
+            }
+        }
+
+        public void llPointAt()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llPointAt");
+        }
+
+        public void llStopPointAt()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llStopPointAt");
+        }
+
+        public void llTargetOmega(LSL_Types.Vector3 axis, double spinrate, double gain)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.RotationalVelocity = new LLVector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
+            m_host.AngularVelocity = new LLVector3((float)(axis.x * spinrate), (float)(axis.y * spinrate), (float)(axis.z * spinrate));
+            m_host.ScheduleTerseUpdate();
+            m_host.SendTerseUpdateToAllClients();
+        }
+
+        public LSL_Types.LSLInteger llGetStartParameter()
+        {
+            m_host.AddScriptLPS(1);
+            // NotImplemented("llGetStartParameter");
+            return m_host.ParentGroup.StartParameter;
+        }
+
+        public void llGodLikeRezObject(string inventory, LSL_Types.Vector3 pos)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGodLikeRezObject");
+        }
+
+        public void llRequestPermissions(string agent, int perm)
+        {
+            LLUUID agentID=new LLUUID();
+
+            if (!LLUUID.TryParse(agent, out agentID))
+                return;
+
+            LLUUID invItemID=InventorySelf();
+
+            if (invItemID == LLUUID.Zero)
+                return; // Not in a prim? How??
+
+            if (agentID == LLUUID.Zero || perm == 0) // Releasing permissions
+            {
+                m_host.TaskInventory[invItemID].PermsGranter=LLUUID.Zero;
+                m_host.TaskInventory[invItemID].PermsMask=0;
+
+                m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
+                        "run_time_permissions", new Object[] {
+                        new LSL_Types.LSLInteger(0) },
+                        new XDetectParams[0]));
+
+                return;
+            }
+
+            m_host.AddScriptLPS(1);
+
+            if (m_host.ParentGroup.RootPart.m_IsAttachment && agent == m_host.ParentGroup.RootPart.m_attachedAvatar)
+            {
+                // When attached, certain permissions are implicit if requested from owner
+                int implicitPerms = BuiltIn_Commands_BaseClass.PERMISSION_TAKE_CONTROLS |
+                        BuiltIn_Commands_BaseClass.PERMISSION_TRIGGER_ANIMATION |
+                        BuiltIn_Commands_BaseClass.PERMISSION_ATTACH;
+
+                if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
+                {
+                    m_host.TaskInventory[invItemID].PermsGranter=agentID;
+                    m_host.TaskInventory[invItemID].PermsMask=perm;
+
+                    m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
+                            "run_time_permissions", new Object[] {
+                            new LSL_Types.LSLInteger(perm) },
+                            new XDetectParams[0]));
+
+                    return;
+                }
+            }
+            else if (m_host.m_sitTargetAvatar == agentID) // Sitting avatar
+            {
+                // When agent is sitting, certain permissions are implicit if requested from sitting agent
+                int implicitPerms = BuiltIn_Commands_BaseClass.PERMISSION_TRIGGER_ANIMATION |
+                        BuiltIn_Commands_BaseClass.PERMISSION_TRACK_CAMERA;
+
+                if ((perm & (~implicitPerms)) == 0) // Requested only implicit perms
+                {
+                    m_host.TaskInventory[invItemID].PermsGranter=agentID;
+                    m_host.TaskInventory[invItemID].PermsMask=perm;
+
+                    m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
+                            "run_time_permissions", new Object[] {
+                            new LSL_Types.LSLInteger(perm) },
+                            new XDetectParams[0]));
+
+                    return;
+                }
+            }
+
+            ScenePresence presence = World.GetScenePresence(agentID);
+
+            if (presence != null)
+            {
+                string ownerName=resolveName(m_host.ParentGroup.RootPart.OwnerID);
+                if (ownerName == String.Empty)
+                    ownerName="(hippos)";
+
+                if (!m_waitingForScriptAnswer)
+                {
+                    m_host.TaskInventory[invItemID].PermsGranter=agentID;
+                    m_host.TaskInventory[invItemID].PermsMask=0;
+                    presence.ControllingClient.OnScriptAnswer+=handleScriptAnswer;
+                    m_waitingForScriptAnswer=true;
+                }
+
+                presence.ControllingClient.SendScriptQuestion(m_host.UUID, m_host.ParentGroup.RootPart.Name, ownerName, invItemID, perm);
+                return;
+            }
+
+            // Requested agent is not in range, refuse perms
+            m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
+                    "run_time_permissions", new Object[] {
+                    new LSL_Types.LSLInteger(0) },
+                    new XDetectParams[0]));
+        }
+
+        void handleScriptAnswer(IClientAPI client, LLUUID taskID, LLUUID itemID, int answer)
+        {
+            if (taskID != m_host.UUID)
+                return;
+
+            LLUUID invItemID=InventorySelf();
+
+            if (invItemID == LLUUID.Zero)
+                return;
+
+            client.OnScriptAnswer-=handleScriptAnswer;
+            m_waitingForScriptAnswer=false;
+
+            m_host.TaskInventory[invItemID].PermsMask=answer;
+            m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
+                    "run_time_permissions", new Object[] {
+                    new LSL_Types.LSLInteger(answer) },
+                    new XDetectParams[0]));
+        }
+
+        public string llGetPermissionsKey()
+        {
+            m_host.AddScriptLPS(1);
+
+            foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
+            {
+                if (item.Type == 10 && item.ItemID == m_itemID)
+                {
+                    return item.PermsGranter.ToString();
+                }
+            }
+
+            return LLUUID.Zero.ToString();
+        }
+
+        public LSL_Types.LSLInteger llGetPermissions()
+        {
+            m_host.AddScriptLPS(1);
+
+            foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
+            {
+                if (item.Type == 10 && item.ItemID == m_itemID)
+                {
+                    return item.PermsMask;
+                }
+            }
+
+            return 0;
+        }
+
+        public LSL_Types.LSLInteger llGetLinkNumber()
+        {
+            m_host.AddScriptLPS(1);
+
+            if (m_host.ParentGroup.Children.Count > 0)
+            {
+                return m_host.LinkNum + 1;
+            }
+            else
+            {
+                return 0;
+            }
+        }
+
+        public void llSetLinkColor(int linknumber, LSL_Types.Vector3 color, int face)
+        {
+            m_host.AddScriptLPS(1);
+            SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknumber);
+            if (linknumber > -1)
+            {
+                LLObject.TextureEntry tex = part.Shape.Textures;
+                LLColor texcolor;
+                if (face > -1)
+                {
+                    texcolor = tex.CreateFace((uint)face).RGBA;
+                    texcolor.R = (float)Math.Abs(color.x - 1);
+                    texcolor.G = (float)Math.Abs(color.y - 1);
+                    texcolor.B = (float)Math.Abs(color.z - 1);
+                    tex.FaceTextures[face].RGBA = texcolor;
+                    part.UpdateTexture(tex);
+                    return;
+                }
+                else if (face == -1)
+                {
+                    texcolor = tex.DefaultTexture.RGBA;
+                    texcolor.R = (float)Math.Abs(color.x - 1);
+                    texcolor.G = (float)Math.Abs(color.y - 1);
+                    texcolor.B = (float)Math.Abs(color.z - 1);
+                    tex.DefaultTexture.RGBA = texcolor;
+                    for (uint i = 0; i < 32; i++)
+                    {
+                        if (tex.FaceTextures[i] != null)
+                        {
+                            texcolor = tex.FaceTextures[i].RGBA;
+                            texcolor.R = (float)Math.Abs(color.x - 1);
+                            texcolor.G = (float)Math.Abs(color.y - 1);
+                            texcolor.B = (float)Math.Abs(color.z - 1);
+                            tex.FaceTextures[i].RGBA = texcolor;
+                        }
+                    }
+                    texcolor = tex.DefaultTexture.RGBA;
+                    texcolor.R = (float)Math.Abs(color.x - 1);
+                    texcolor.G = (float)Math.Abs(color.y - 1);
+                    texcolor.B = (float)Math.Abs(color.z - 1);
+                    tex.DefaultTexture.RGBA = texcolor;
+                    part.UpdateTexture(tex);
+                    return;
+                }
+                return;
+            }
+            else if (linknumber == -1)
+            {
+                int num = m_host.ParentGroup.PrimCount;
+                for (int w = 0; w < num; w++)
+                {
+                    linknumber = w;
+                    part = m_host.ParentGroup.GetLinkNumPart(linknumber);
+                    LLObject.TextureEntry tex = part.Shape.Textures;
+                    LLColor texcolor;
+                    if (face > -1)
+                    {
+                        texcolor = tex.CreateFace((uint)face).RGBA;
+                        texcolor.R = (float)Math.Abs(color.x - 1);
+                        texcolor.G = (float)Math.Abs(color.y - 1);
+                        texcolor.B = (float)Math.Abs(color.z - 1);
+                        tex.FaceTextures[face].RGBA = texcolor;
+                        part.UpdateTexture(tex);
+                    }
+                    else if (face == -1)
+                    {
+                        texcolor = tex.DefaultTexture.RGBA;
+                        texcolor.R = (float)Math.Abs(color.x - 1);
+                        texcolor.G = (float)Math.Abs(color.y - 1);
+                        texcolor.B = (float)Math.Abs(color.z - 1);
+                        tex.DefaultTexture.RGBA = texcolor;
+                        for (uint i = 0; i < 32; i++)
+                        {
+                            if (tex.FaceTextures[i] != null)
+                            {
+                                texcolor = tex.FaceTextures[i].RGBA;
+                                texcolor.R = (float)Math.Abs(color.x - 1);
+                                texcolor.G = (float)Math.Abs(color.y - 1);
+                                texcolor.B = (float)Math.Abs(color.z - 1);
+                                tex.FaceTextures[i].RGBA = texcolor;
+                            }
+                        }
+                        texcolor = tex.DefaultTexture.RGBA;
+                        texcolor.R = (float)Math.Abs(color.x - 1);
+                        texcolor.G = (float)Math.Abs(color.y - 1);
+                        texcolor.B = (float)Math.Abs(color.z - 1);
+                        tex.DefaultTexture.RGBA = texcolor;
+                        part.UpdateTexture(tex);
+                    }
+                }
+                return;
+            }
+        }
+
+        public void llCreateLink(string target, int parent)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llCreateLink");
+        }
+
+        public void llBreakLink(int linknum)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llBreakLink");
+        }
+
+        public void llBreakAllLinks()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llBreakAllLinks");
+        }
+
+        public string llGetLinkKey(int linknum)
+        {
+            m_host.AddScriptLPS(1);
+            SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
+            if (part != null)
+            {
+                return part.UUID.ToString();
+            }
+            else
+            {
+                return LLUUID.Zero.ToString();
+            }
+        }
+
+        public string llGetLinkName(int linknum)
+        {
+            m_host.AddScriptLPS(1);
+            SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknum);
+            if (part != null)
+            {
+                return part.Name;
+            }
+            else
+            {
+                return LLUUID.Zero.ToString();
+            }
+        }
+
+        public LSL_Types.LSLInteger llGetInventoryNumber(int type)
+        {
+            m_host.AddScriptLPS(1);
+            int count = 0;
+            foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
+            {
+                if (inv.Value.Type == type || type == -1)
+                {
+                    count = count + 1;
+                }
+            }
+            return count;
+        }
+
+        public string llGetInventoryName(int type, int number)
+        {
+            m_host.AddScriptLPS(1);
+            ArrayList keys = new ArrayList();
+            foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
+            {
+                if (inv.Value.Type == type || type == -1)
+                {
+                    keys.Add(inv.Value.Name);
+                }
+            }
+            if (keys.Count == 0)
+            {
+                return String.Empty;
+            }
+            keys.Sort();
+            if (keys.Count > number)
+            {
+                return (string)keys[number];
+            }
+            return String.Empty;
+        }
+
+        public void llSetScriptState(string name, int run)
+        {
+            LLUUID item;
+
+            m_host.AddScriptLPS(1);
+
+            // These functions are supposed to be robust,
+            // so get the state one step at a time.
+
+            if ((item = ScriptByName(name)) != LLUUID.Zero)
+            {
+                m_ScriptEngine.SetScriptState(item, run == 0 ? false : true);
+            }
+            else
+            {
+                ShoutError("llSetScriptState: script "+name+" not found");
+            }
+        }
+
+        public double llGetEnergy()
+        {
+            m_host.AddScriptLPS(1);
+            // TODO: figure out real energy value
+            return 1.0f;
+        }
+
+        public void llGiveInventory(string destination, string inventory)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGiveInventory");
+        }
+
+        public void llRemoveInventory(string item)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llRemoveInventory");
+        }
+
+        public void llSetText(string text, LSL_Types.Vector3 color, double alpha)
+        {
+            m_host.AddScriptLPS(1);
+            Vector3 av3 = new Vector3((float)color.x, (float)color.y, (float)color.z);
+            m_host.SetText(text, av3, alpha);
+        }
+
+        public double llWater(LSL_Types.Vector3 offset)
+        {
+            m_host.AddScriptLPS(1);
+            return World.RegionInfo.EstateSettings.waterHeight;
+        }
+
+        public void llPassTouches(int pass)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llPassTouches");
+        }
+
+        public string llRequestAgentData(string id, int data)
+        {
+            m_host.AddScriptLPS(1);
+
+            UserProfileData userProfile =
+                    World.CommsManager.UserService.GetUserProfile(id);
+
+            string reply = String.Empty;
+
+            switch(data)
+            {
+            case 1: // DATA_ONLINE (0|1)
+                // TODO: implement fetching of this information
+//                if(userProfile.CurrentAgent.AgentOnline)
+//                    reply = "1";
+//                else
+                    reply = "0";
+                break;
+            case 2: // DATA_NAME (First Last)
+                reply = userProfile.FirstName+" "+userProfile.SurName;
+                break;
+            case 3: // DATA_BORN (YYYY-MM-DD)
+                DateTime born = new DateTime(1970, 1, 1, 0, 0, 0, 0);
+                born = born.AddSeconds(userProfile.Created);
+                reply = born.ToString("yyyy-MM-dd");
+                break;
+            case 4: // DATA_RATING (0,0,0,0,0,0)
+                reply = "0,0,0,0,0,0";
+                break;
+            case 8: // DATA_PAYINFO (0|1|2|3)
+                reply = "0";
+                break;
+            default:
+                return LLUUID.Zero.ToString(); // Raise no event
+            }
+
+            LLUUID rq = LLUUID.Random();
+
+            LLUUID tid = m_ScriptEngine.m_ASYNCLSLCommandManager.
+                    m_Dataserver.RegisterRequest(m_localID,
+                    m_itemID, rq.ToString());
+
+            m_ScriptEngine.m_ASYNCLSLCommandManager.
+            m_Dataserver.DataserverReply(rq.ToString(), reply);
+
+            return tid.ToString();
+        }
+
+        public string llRequestInventoryData(string name)
+        {
+            m_host.AddScriptLPS(1);
+
+            foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
+            {
+                if (item.Type == 3 && item.Name == name)
+                {
+                    LLUUID tid = m_ScriptEngine.m_ASYNCLSLCommandManager.
+                            m_Dataserver.RegisterRequest(m_localID,
+                            m_itemID, item.AssetID.ToString());
+
+                    LLVector3 region = new LLVector3(
+                        World.RegionInfo.RegionLocX * Constants.RegionSize,
+                        World.RegionInfo.RegionLocY * Constants.RegionSize,
+                        0);
+
+                    World.AssetCache.GetAsset(item.AssetID,
+                        delegate(LLUUID i, AssetBase a)
+                        {
+                            AssetLandmark lm = new AssetLandmark(a);
+
+                            region += lm.Position;
+
+                            string reply = region.ToString();
+
+                            m_ScriptEngine.m_ASYNCLSLCommandManager.
+                                    m_Dataserver.DataserverReply(i.ToString(),
+                                    reply);
+                        }, false);
+
+                    return tid.ToString();
+                }
+            }
+
+            return String.Empty;
+        }
+
+        public void llSetDamage(double damage)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetDamage");
+        }
+
+        public void llTeleportAgentHome(string agent)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llTeleportAgentHome");
+        }
+
+        public void llModifyLand(int action, int brush)
+        {
+            m_host.AddScriptLPS(1);
+            World.ExternalChecks.ExternalChecksCanTerraformLand(m_host.OwnerID, new LLVector3(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, 0));
+        }
+
+        public void llCollisionSound(string impact_sound, double impact_volume)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llCollisionSound");
+        }
+
+        public void llCollisionSprite(string impact_sprite)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llCollisionSprite");
+        }
+
+        public string llGetAnimation(string id)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetAnimation");
+            return String.Empty;
+        }
+
+        public void llResetScript()
+        {
+            m_host.AddScriptLPS(1);
+            m_ScriptEngine.ResetScript(m_itemID);
+        }
+
+        public void llMessageLinked(int linknum, int num, string msg, string id)
+        {
+
+            m_host.AddScriptLPS(1);
+
+            uint partLocalID;
+            LLUUID partItemID;
+
+            switch ((int)linknum)
+            {
+
+                case (int)BuiltIn_Commands_BaseClass.LINK_ROOT:
+
+                    SceneObjectPart part = m_host.ParentGroup.RootPart;
+
+                    foreach (TaskInventoryItem item in part.TaskInventory.Values)
+                    {
+                        if (item.Type == 10)
+                        {
+                            partLocalID = part.LocalId;
+                            partItemID = item.ItemID;
+
+                            object[] resobj = new object[]
+                            {
+                                new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
+                            };
+
+                            m_ScriptEngine.PostScriptEvent(partItemID,
+                                    new XEventParams("link_message",
+                                    resobj, new XDetectParams[0]));
+                        }
+                    }
+
+                    break;
+
+                case (int)BuiltIn_Commands_BaseClass.LINK_SET:
+
+                    Console.WriteLine("LINK_SET");
+
+                    foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
+                    {
+
+                        foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
+                        {
+                            if (item.Type == 10)
+                            {
+                                partLocalID = partInst.LocalId;
+                                partItemID = item.ItemID;
+                                Object[] resobj = new object[]
+                                {
+                                    new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
+                                };
+
+                                m_ScriptEngine.PostScriptEvent(partItemID,
+                                        new XEventParams("link_message",
+                                        resobj, new XDetectParams[0]));
+                            }
+                        }
+                    }
+
+                    break;
+
+                case (int)BuiltIn_Commands_BaseClass.LINK_ALL_OTHERS:
+
+                    foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
+                    {
+
+                        if (partInst.LocalId != m_host.LocalId)
+                        {
+
+                            foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
+                            {
+                                if (item.Type == 10)
+                                {
+                                    partLocalID = partInst.LocalId;
+                                    partItemID = item.ItemID;
+                                    Object[] resobj = new object[]
+                                    {
+                                        new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
+                                    };
+
+                                    m_ScriptEngine.PostScriptEvent(partItemID,
+                                            new XEventParams("link_message",
+                                            resobj, new XDetectParams[0]));
+                                }
+                            }
+
+                        }
+                    }
+
+                    break;
+
+                case (int)BuiltIn_Commands_BaseClass.LINK_ALL_CHILDREN:
+
+                    foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
+                    {
+
+                        if (partInst.LocalId != m_host.ParentGroup.RootPart.LocalId)
+                        {
+
+                            foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
+                            {
+                                if (item.Type == 10)
+                                {
+                                    partLocalID = partInst.LocalId;
+                                    partItemID = item.ItemID;
+                                    Object[] resobj = new object[]
+                                    {
+                                        new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
+                                    };
+
+                                    m_ScriptEngine.PostScriptEvent(partItemID,
+                                            new XEventParams("link_message",
+                                            resobj, new XDetectParams[0]));
+                                }
+                            }
+
+                        }
+                    }
+
+                    break;
+
+                case (int)BuiltIn_Commands_BaseClass.LINK_THIS:
+
+                    foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
+                    {
+                        if (item.Type == 10)
+                        {
+                            partItemID = item.ItemID;
+
+                            object[] resobj = new object[]
+                            {
+                                new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
+                            };
+
+                            m_ScriptEngine.PostScriptEvent(partItemID,
+                                    new XEventParams("link_message",
+                                    resobj, new XDetectParams[0]));
+                        }
+                    }
+
+                    break;
+
+                default:
+
+                    foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
+                    {
+
+                        if ((partInst.LinkNum + 1) == linknum)
+                        {
+
+                            foreach (TaskInventoryItem item in partInst.TaskInventory.Values)
+                            {
+                                if (item.Type == 10)
+                                {
+                                    partLocalID = partInst.LocalId;
+                                    partItemID = item.ItemID;
+                                    Object[] resObjDef = new object[]
+                                    {
+                                        new LSL_Types.LSLInteger(m_host.LinkNum + 1), new LSL_Types.LSLInteger(num), new LSL_Types.LSLString(msg), new LSL_Types.LSLString(id)
+                                    };
+
+                                    m_ScriptEngine.PostScriptEvent(partItemID,
+                                            new XEventParams("link_message",
+                                            resObjDef, new XDetectParams[0]));
+                                }
+                            }
+
+                        }
+                    }
+
+                    break;
+
+            }
+
+        }
+
+        public void llPushObject(string target, LSL_Types.Vector3 impulse, LSL_Types.Vector3 ang_impulse, int local)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llPushObject");
+        }
+
+        public void llPassCollisions(int pass)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llPassCollisions");
+        }
+
+        public string llGetScriptName()
+        {
+
+            string result = String.Empty;
+
+            m_host.AddScriptLPS(1);
+
+            foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
+            {
+                if (item.Type == 10 && item.ItemID == m_itemID)
+                {
+                    result =  item.Name!=null?item.Name:String.Empty;
+                    break;
+                }
+            }
+
+            return result;
+
+        }
+
+        public LSL_Types.LSLInteger llGetNumberOfSides()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetNumberOfSides");
+            return 0;
+        }
+
+
+        /* The new / changed functions were tested with the following LSL script:
+
+        default
+        {
+            state_entry()
+            {
+                rotation rot = llEuler2Rot(<0,70,0> * DEG_TO_RAD);
+
+                llOwnerSay("to get here, we rotate over: "+ (string) llRot2Axis(rot));
+                llOwnerSay("and we rotate for: "+ (llRot2Angle(rot) * RAD_TO_DEG));
+
+                // convert back and forth between quaternion <-> vector and angle
+
+                rotation newrot = llAxisAngle2Rot(llRot2Axis(rot),llRot2Angle(rot));
+
+                llOwnerSay("Old rotation was: "+(string) rot);
+                llOwnerSay("re-converted rotation is: "+(string) newrot);
+
+                llSetRot(rot);  // to check the parameters in the prim
+            }
+        }
+        */
+
+
+
+        // Xantor 29/apr/2008
+        // Returns rotation described by rotating angle radians about axis.
+        // q = cos(a/2) + i (x * sin(a/2)) + j (y * sin(a/2)) + k (z * sin(a/2))
+        public LSL_Types.Quaternion llAxisAngle2Rot(LSL_Types.Vector3 axis, double angle)
+        {
+            m_host.AddScriptLPS(1);
+
+            double x, y, z, s, t;
+
+            s = Math.Cos(angle / 2);
+            t = Math.Sin(angle / 2); // temp value to avoid 2 more sin() calcs
+            x = axis.x * t;
+            y = axis.y * t;
+            z = axis.z * t;
+
+            return new LSL_Types.Quaternion(x,y,z,s);
+            // NotImplemented("llAxisAngle2Rot");
+        }
+
+
+        // Xantor 29/apr/2008
+        // converts a Quaternion to X,Y,Z axis rotations
+        public LSL_Types.Vector3 llRot2Axis(LSL_Types.Quaternion rot)
+        {
+            m_host.AddScriptLPS(1);
+            double x,y,z;
+
+            if (rot.s > 1) // normalization needed
+            {
+                double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
+                        rot.z * rot.z + rot.s * rot.s);
+
+                rot.x /= length;
+                rot.y /= length;
+                rot.z /= length;
+                rot.s /= length;
+
+            }
+
+            double angle = 2 * Math.Acos(rot.s);
+            double s = Math.Sqrt(1 - rot.s * rot.s);
+            if (s < 0.001)
+            {
+                x = 1;
+                y = z = 0;
+            }
+            else
+            {
+                x = rot.x / s; // normalise axis
+                y = rot.y / s;
+                z = rot.z / s;
+            }
+
+
+            return new LSL_Types.Vector3(x,y,z);
+
+
+//            NotImplemented("llRot2Axis");
+        }
+
+
+        // Returns the angle of a quaternion (see llRot2Axis for the axis)
+        public double llRot2Angle(LSL_Types.Quaternion rot)
+        {
+            m_host.AddScriptLPS(1);
+
+            if (rot.s > 1) // normalization needed
+            {
+                double length = Math.Sqrt(rot.x * rot.x + rot.y * rot.y +
+                        rot.z * rot.z + rot.s * rot.s);
+
+                rot.x /= length;
+                rot.y /= length;
+                rot.z /= length;
+                rot.s /= length;
+
+            }
+
+            double angle = 2 * Math.Acos(rot.s);
+
+            return angle;
+
+//            NotImplemented("llRot2Angle");
+        }
+
+        public double llAcos(double val)
+        {
+            m_host.AddScriptLPS(1);
+            return (double)Math.Acos(val);
+        }
+
+        public double llAsin(double val)
+        {
+            m_host.AddScriptLPS(1);
+            return (double)Math.Asin(val);
+        }
+
+        // Xantor 30/apr/2008
+        public double llAngleBetween(LSL_Types.Quaternion a, LSL_Types.Quaternion b)
+        {
+            m_host.AddScriptLPS(1);
+
+           return (double) Math.Acos(a.x * b.x + a.y * b.y + a.z * b.z + a.s * b.s) * 2;
+//            NotImplemented("llAngleBetween");
+        }
+
+        public string llGetInventoryKey(string name)
+        {
+            m_host.AddScriptLPS(1);
+            foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
+            {
+                if (inv.Value.Name == name)
+                {
+                    if ((inv.Value.OwnerMask & (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify)) == (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify))
+                    {
+                        return inv.Value.AssetID.ToString();
+                    }
+                    else
+                    {
+                        return LLUUID.Zero.ToString();
+                    }
+                }
+            }
+            return LLUUID.Zero.ToString();
+        }
+
+        public void llAllowInventoryDrop(int add)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llAllowInventoryDrop");
+        }
+
+        public LSL_Types.Vector3 llGetSunDirection()
+        {
+            m_host.AddScriptLPS(1);
+
+            LSL_Types.Vector3 SunDoubleVector3;
+            LLVector3 SunFloatVector3;
+
+            // sunPosition estate setting is set in OpenSim.Region.Environment.Modules.SunModule
+            // have to convert from LLVector3 (float) to LSL_Types.Vector3 (double)
+            SunFloatVector3 = World.RegionInfo.EstateSettings.sunPosition;
+            SunDoubleVector3.x = (double)SunFloatVector3.X;
+            SunDoubleVector3.y = (double)SunFloatVector3.Y;
+            SunDoubleVector3.z = (double)SunFloatVector3.Z;
+
+            return SunDoubleVector3;
+        }
+
+        public LSL_Types.Vector3 llGetTextureOffset(int face)
+        {
+            m_host.AddScriptLPS(1);
+            LLObject.TextureEntry tex = m_host.Shape.Textures;
+            LSL_Types.Vector3 offset;
+            if (face == -1)
+            {
+                face = 0;
+            }
+            offset.x = tex.GetFace((uint)face).OffsetU;
+            offset.y = tex.GetFace((uint)face).OffsetV;
+            offset.z = 0.0;
+            return offset;
+        }
+
+        public LSL_Types.Vector3 llGetTextureScale(int side)
+        {
+            m_host.AddScriptLPS(1);
+            LLObject.TextureEntry tex = m_host.Shape.Textures;
+            LSL_Types.Vector3 scale;
+            if (side == -1)
+            {
+                side = 0;
+            }
+            scale.x = tex.GetFace((uint)side).RepeatU;
+            scale.y = tex.GetFace((uint)side).RepeatV;
+            scale.z = 0.0;
+            return scale;
+        }
+
+        public double llGetTextureRot(int face)
+        {
+            m_host.AddScriptLPS(1);
+            LLObject.TextureEntry tex = m_host.Shape.Textures;
+            if (face == -1)
+            {
+                face = 0;
+            }
+            return tex.GetFace((uint)face).Rotation;
+        }
+
+        public LSL_Types.LSLInteger llSubStringIndex(string source, string pattern)
+        {
+            m_host.AddScriptLPS(1);
+            return source.IndexOf(pattern);
+        }
+
+        public string llGetOwnerKey(string id)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID key = new LLUUID();
+            if (LLUUID.TryParse(id, out key))
+            {
+                return World.GetSceneObjectPart(World.Entities[key].LocalId).OwnerID.ToString();
+            }
+            else
+            {
+                return LLUUID.Zero.ToString();
+            }
+        }
+
+        public LSL_Types.Vector3 llGetCenterOfMass()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetCenterOfMass");
+            return new LSL_Types.Vector3();
+        }
+
+        public LSL_Types.list llListSort(LSL_Types.list src, int stride, int ascending)
+        {
+            m_host.AddScriptLPS(1);
+            return src.Sort(stride, ascending);
+        }
+
+        public LSL_Types.LSLInteger llGetListLength(LSL_Types.list src)
+        {
+            m_host.AddScriptLPS(1);
+            return src.Length;
+        }
+
+        public LSL_Types.LSLInteger llList2Integer(LSL_Types.list src, int index)
+        {
+            m_host.AddScriptLPS(1);
+            if (index < 0)
+            {
+                index = src.Length + index;
+            }
+            if (index >= src.Length)
+            {
+                return 0;
+            }
+            try
+            {
+                return Convert.ToInt32(src.Data[index]);
+            }
+            catch (FormatException)
+            {
+                return 0;
+            }
+        }
+
+        public double osList2Double(LSL_Types.list src, int index)
+        {
+            m_host.AddScriptLPS(1);
+            if (index < 0)
+            {
+                index = src.Length + index;
+            }
+            if (index >= src.Length)
+            {
+                return 0.0;
+            }
+            return Convert.ToDouble(src.Data[index]);
+        }
+
+        public double llList2Float(LSL_Types.list src, int index)
+        {
+            m_host.AddScriptLPS(1);
+            if (index < 0)
+            {
+                index = src.Length + index;
+            }
+            if (index >= src.Length)
+            {
+                return 0.0;
+            }
+            try
+            {
+                return Convert.ToDouble(src.Data[index]);
+            }
+            catch (FormatException)
+            {
+                return 0.0;
+            }
+        }
+
+        public string llList2String(LSL_Types.list src, int index)
+        {
+            m_host.AddScriptLPS(1);
+            if (index < 0)
+            {
+                index = src.Length + index;
+            }
+            if (index >= src.Length)
+            {
+                return String.Empty;
+            }
+            return src.Data[index].ToString();
+        }
+
+        public string llList2Key(LSL_Types.list src, int index)
+        {
+            m_host.AddScriptLPS(1);
+            if (index < 0)
+            {
+                index = src.Length + index;
+            }
+            if (index >= src.Length)
+            {
+                return "";
+            }
+            return src.Data[index].ToString();
+        }
+
+        public LSL_Types.Vector3 llList2Vector(LSL_Types.list src, int index)
+        {
+            m_host.AddScriptLPS(1);
+            if (index < 0)
+            {
+                index = src.Length + index;
+            }
+            if (index >= src.Length)
+            {
+                return new LSL_Types.Vector3(0, 0, 0);
+            }
+            if (src.Data[index].GetType() == typeof(LSL_Types.Vector3))
+            {
+                return (LSL_Types.Vector3)src.Data[index];
+            }
+            else
+            {
+                return new LSL_Types.Vector3(src.Data[index].ToString());
+            }
+        }
+
+        public LSL_Types.Quaternion llList2Rot(LSL_Types.list src, int index)
+        {
+            m_host.AddScriptLPS(1);
+            if (index < 0)
+            {
+                index = src.Length + index;
+            }
+            if (index >= src.Length)
+            {
+                return new LSL_Types.Quaternion(0, 0, 0, 1);
+            }
+            if (src.Data[index].GetType() == typeof(LSL_Types.Quaternion))
+            {
+                return (LSL_Types.Quaternion)src.Data[index];
+            }
+            else
+            {
+                return new LSL_Types.Quaternion(src.Data[index].ToString());
+            }
+        }
+
+        public LSL_Types.list llList2List(LSL_Types.list src, int start, int end)
+        {
+            m_host.AddScriptLPS(1);
+            return src.GetSublist(start, end);
+        }
+
+        public LSL_Types.list llDeleteSubList(LSL_Types.list src, int start, int end)
+        {
+            return src.DeleteSublist(end, start);
+        }
+
+        public LSL_Types.LSLInteger llGetListEntryType(LSL_Types.list src, int index)
+        {
+            m_host.AddScriptLPS(1);
+            if (index < 0)
+            {
+                index = src.Length + index;
+            }
+            if (index >= src.Length)
+            {
+                return 0;
+            }
+
+            if (src.Data[index] is Int32)
+                return 1;
+            if (src.Data[index] is Double)
+                return 2;
+            if (src.Data[index] is String)
+            {
+                LLUUID tuuid;
+                if (LLUUID.TryParse(src.Data[index].ToString(), out tuuid))
+                {
+                    return 3;
+                }
+                else
+                {
+                    return 4;
+                }
+            }
+            if (src.Data[index] is LSL_Types.Vector3)
+                return 5;
+            if (src.Data[index] is LSL_Types.Quaternion)
+                return 6;
+            if (src.Data[index] is LSL_Types.list)
+                return 7;
+            return 0;
+
+        }
+
+        /// <summary>
+        /// Process the supplied list and return the
+        /// content of the list formatted as a comma
+        /// separated list. There is a space after
+        /// each comma.
+        /// </summary>
+
+        public string llList2CSV(LSL_Types.list src)
+        {
+
+            string ret = String.Empty;
+            int    x   = 0;
+
+            m_host.AddScriptLPS(1);
+
+            if (src.Data.Length > 0)
+            {
+                ret = src.Data[x++].ToString();
+                for (; x < src.Data.Length; x++)
+                {
+                    ret += ", "+src.Data[x].ToString();
+                }
+            }
+
+            return ret;
+        }
+
+        /// <summary>
+        /// The supplied string is scanned for commas
+        /// and converted into a list. Commas are only
+        /// effective if they are encountered outside
+        /// of '<' '>' delimiters. Any whitespace
+        /// before or after an element is trimmed.
+        /// </summary>
+
+        public LSL_Types.list llCSV2List(string src)
+        {
+
+            LSL_Types.list result = new LSL_Types.list();
+            int parens = 0;
+            int start  = 0;
+            int length = 0;
+
+            m_host.AddScriptLPS(1);
+
+            for (int i = 0; i < src.Length; i++)
+            {
+                switch (src[i])
+                {
+                    case '<' :
+                        parens++;
+                        length++;
+                        break;
+                    case '>' :
+                        if (parens > 0)
+                            parens--;
+                        length++;
+                        break;
+                    case ',' :
+                        if (parens == 0)
+                        {
+                            result.Add(src.Substring(start,length).Trim());
+                            start += length+1;
+                            length = 0;
+                        } else
+                            length++;
+                        break;
+                    default  :
+                        length++;
+                        break;
+                }
+            }
+
+            result.Add(src.Substring(start,length).Trim());
+
+            return result;
+
+        }
+
+        ///  <summary>
+        ///  Randomizes the list, be arbitrarily reordering
+        ///  sublists of stride elements. As the stride approaches
+        ///  the size of the list, the options become very
+        ///  limited.
+        ///  </summary>
+        ///  <remarks>
+        ///  This could take a while for very large list
+        ///  sizes.
+        ///  </remarks>
+
+        public LSL_Types.list llListRandomize(LSL_Types.list src, int stride)
+        {
+
+            LSL_Types.list result;
+            Random rand           = new Random();
+
+            int   chunkk;
+            int[] chunks;
+            int   index1;
+            int   index2;
+            int   tmp;
+
+            m_host.AddScriptLPS(1);
+
+            if (stride == 0)
+                stride = 1;
+
+            // Stride MUST be a factor of the list length
+            // If not, then return the src list. This also
+            // traps those cases where stride > length.
+
+            if (src.Length != stride && src.Length%stride == 0)
+            {
+                chunkk = src.Length/stride;
+
+                chunks = new int[chunkk];
+
+                for (int i = 0; i < chunkk; i++)
+                    chunks[i] = i;
+
+                for (int i = 0; i < chunkk - 1; i++)
+                {
+                    //  randomly select 2 chunks
+                    index1 = rand.Next(rand.Next(65536));
+                    index1 = index1%chunkk;
+                    index2 = rand.Next(rand.Next(65536));
+                    index2 = index2%chunkk;
+
+                    //  and swap their relative positions
+                    tmp = chunks[index1];
+                    chunks[index1] = chunks[index2];
+                    chunks[index2] = tmp;
+                }
+
+                // Construct the randomized list
+
+                result = new LSL_Types.list();
+
+                for (int i = 0; i < chunkk; i++)
+                {
+                    for (int j = 0; j < stride; j++)
+                    {
+                        result.Add(src.Data[chunks[i]*stride+j]);
+                    }
+                }
+            }
+            else {
+                object[] array = new object[src.Length];
+                Array.Copy(src.Data, 0, array, 0, src.Length);
+                result = new LSL_Types.list(array);
+            }
+
+            return result;
+
+        }
+
+        /// <summary>
+        /// Elements in the source list starting with 0 and then
+        /// every i+stride. If the stride is negative then the scan
+        /// is backwards producing an inverted result.
+        /// Only those elements that are also in the specified
+        /// range are included in the result.
+        /// </summary>
+
+        public LSL_Types.list llList2ListStrided(LSL_Types.list src, int start, int end, int stride)
+        {
+
+            LSL_Types.list result = new LSL_Types.list();
+            int[] si = new int[2];
+            int[] ei = new int[2];
+            bool twopass = false;
+
+            m_host.AddScriptLPS(1);
+
+            //  First step is always to deal with negative indices
+
+            if (start < 0)
+                start = src.Length+start;
+            if (end   < 0)
+                end   = src.Length+end;
+
+            //  Out of bounds indices are OK, just trim them
+            //  accordingly
+
+            if (start > src.Length)
+                start = src.Length;
+
+            if (end > src.Length)
+                end = src.Length;
+
+            //  There may be one or two ranges to be considered
+
+            if (start != end)
+            {
+
+                if (start <= end)
+                {
+                   si[0] = start;
+                   ei[0] = end;
+                }
+                else
+                {
+                   si[1] = start;
+                   ei[1] = src.Length;
+                   si[0] = 0;
+                   ei[0] = end;
+                   twopass = true;
+                }
+
+                //  The scan always starts from the beginning of the
+                //  source list, but members are only selected if they
+                //  fall within the specified sub-range. The specified
+                //  range values are inclusive.
+                //  A negative stride reverses the direction of the
+                //  scan producing an inverted list as a result.
+
+                if (stride == 0)
+                    stride = 1;
+
+                if (stride > 0)
+                {
+                    for (int i = 0; i < src.Length; i += stride)
+                    {
+                        if (i<=ei[0] && i>=si[0])
+                            result.Add(src.Data[i]);
+                        if (twopass && i>=si[1] && i<=ei[1])
+                            result.Add(src.Data[i]);
+                    }
+                }
+                else if (stride < 0)
+                {
+                    for (int i = src.Length - 1; i >= 0; i += stride)
+                    {
+                        if (i <= ei[0] && i >= si[0])
+                            result.Add(src.Data[i]);
+                        if (twopass && i >= si[1] && i <= ei[1])
+                            result.Add(src.Data[i]);
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        public LSL_Types.Vector3 llGetRegionCorner()
+        {
+            m_host.AddScriptLPS(1);
+            return new LSL_Types.Vector3(World.RegionInfo.RegionLocX * Constants.RegionSize, World.RegionInfo.RegionLocY * Constants.RegionSize, 0);
+        }
+
+        /// <summary>
+        /// Insert the list identified by <src> into the
+        /// list designated by <dest> such that the first
+        /// new element has the index specified by <index>
+        /// </summary>
+
+        public LSL_Types.list llListInsertList(LSL_Types.list dest, LSL_Types.list src, int index)
+        {
+
+            LSL_Types.list pref = null;
+            LSL_Types.list suff = null;
+
+            m_host.AddScriptLPS(1);
+
+            if (index < 0)
+            {
+                index = index+dest.Length;
+                if (index < 0)
+                {
+                    index = 0;
+                }
+            }
+
+            if (index != 0)
+            {
+                pref = dest.GetSublist(0,index-1);
+                if (index < dest.Length)
+                {
+                    suff = dest.GetSublist(index,-1);
+                    return pref + src + suff;
+                }
+                else
+                {
+                    return pref + src;
+                }
+            }
+            else
+            {
+                if (index < dest.Length)
+                {
+                    suff = dest.GetSublist(index,-1);
+                    return src + suff;
+                }
+                else
+                {
+                    return src;
+                }
+            }
+
+        }
+
+        /// <summary>
+        /// Returns the index of the first occurrence of test
+        /// in src.
+        /// </summary>
+
+        public LSL_Types.LSLInteger llListFindList(LSL_Types.list src, LSL_Types.list test)
+        {
+
+            int index  = -1;
+            int length = src.Length - test.Length + 1;
+
+            m_host.AddScriptLPS(1);
+
+            // If either list is empty, do not match
+
+            if (src.Length != 0 && test.Length != 0)
+            {
+                for (int i = 0; i < length; i++)
+                {
+                   if (src.Data[i].Equals(test.Data[0]))
+                   {
+                       int j;
+                       for (j = 1; j < test.Length; j++)
+                           if (!src.Data[i+j].Equals(test.Data[j]))
+                               break;
+                       if (j == test.Length)
+                       {
+                           index = i;
+                           break;
+                       }
+                   }
+                }
+            }
+
+            return index;
+
+        }
+
+        public string llGetObjectName()
+        {
+            m_host.AddScriptLPS(1);
+            return m_host.Name!=null?m_host.Name:String.Empty;
+        }
+
+        public void llSetObjectName(string name)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.Name = name!=null?name:String.Empty;
+        }
+
+        public string llGetDate()
+        {
+            m_host.AddScriptLPS(1);
+            DateTime date = DateTime.Now.ToUniversalTime();
+            string result = date.ToString("yyyy-MM-dd");
+            return result;
+        }
+
+        public LSL_Types.LSLInteger llEdgeOfWorld(LSL_Types.Vector3 pos, LSL_Types.Vector3 dir)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llEdgeOfWorld");
+            return 0;
+        }
+
+        public LSL_Types.LSLInteger llGetAgentInfo(string id)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetAgentInfo");
+            return 0;
+        }
+
+        public void llAdjustSoundVolume(double volume)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.AdjustSoundGain(volume);
+        }
+
+        public void llSetSoundQueueing(int queue)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetSoundQueueing");
+        }
+
+        public void llSetSoundRadius(double radius)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetSoundRadius");
+        }
+
+        public string llKey2Name(string id)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID key = new LLUUID();
+            if (LLUUID.TryParse(id,out key))
+            {
+                ScenePresence presence = World.GetScenePresence(key);
+
+                if (presence != null)
+                {
+                    return presence.Name;
+                }
+
+                if (World.GetSceneObjectPart(key) != null)
+                {
+                    return World.GetSceneObjectPart(key).Name;
+                }
+            }
+            return String.Empty;
+        }
+
+
+
+        public void llSetTextureAnim(int mode, int face, int sizex, int sizey, double start, double length, double rate)
+        {
+            m_host.AddScriptLPS(1);
+            Primitive.TextureAnimation pTexAnim = new Primitive.TextureAnimation();
+            pTexAnim.Flags =(uint) mode;
+
+            //ALL_SIDES
+            if (face == -1)
+                    face = 255;
+
+            pTexAnim.Face = (uint)face;
+            pTexAnim.Length = (float)length;
+            pTexAnim.Rate = (float)rate;
+            pTexAnim.SizeX = (uint)sizex;
+            pTexAnim.SizeY = (uint)sizey;
+            pTexAnim.Start = (float)start;
+
+            m_host.AddTextureAnimation(pTexAnim);
+            m_host.SendFullUpdateToAllClients();
+        }
+
+        public void llTriggerSoundLimited(string sound, double volume, LSL_Types.Vector3 top_north_east,
+                                          LSL_Types.Vector3 bottom_south_west)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llTriggerSoundLimited");
+        }
+
+        public void llEjectFromLand(string pest)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llEjectFromLand");
+        }
+
+        public LSL_Types.list llParseString2List(string str, LSL_Types.list separators, LSL_Types.list spacers)
+        {
+            m_host.AddScriptLPS(1);
+            LSL_Types.list ret = new LSL_Types.list();
+            object[] delimiters = new object[separators.Length + spacers.Length];
+            separators.Data.CopyTo(delimiters, 0);
+            spacers.Data.CopyTo(delimiters, separators.Length);
+            bool dfound = false;
+            do
+            {
+                dfound = false;
+                int cindex = -1;
+                string cdeli = "";
+                for (int i = 0; i < delimiters.Length; i++)
+                {
+                    int index = str.IndexOf(delimiters[i].ToString());
+                    bool found = index != -1;
+                    if (found)
+                    {
+                        if ((cindex > index) || (cindex == -1))
+                        {
+                            cindex = index;
+                            cdeli = (string)delimiters[i];
+                        }
+                        dfound = dfound || found;
+                    }
+                }
+                if (cindex != -1)
+                {
+                    if (cindex > 0)
+                    {
+                        ret.Add(str.Substring(0, cindex));
+                        if (spacers.Contains(cdeli))
+                        {
+                            ret.Add(cdeli);
+                        }
+                    }
+                    if (cindex == 0 && spacers.Contains(cdeli))
+                    {
+                        ret.Add(cdeli);
+                    }
+                    str = str.Substring(cindex + cdeli.Length);
+                }
+            } while (dfound);
+            if (str != "")
+            {
+                ret.Add(str);
+            }
+            return ret;
+        }
+
+        public LSL_Types.LSLInteger llOverMyLand(string id)
+        {
+
+            m_host.AddScriptLPS(1);
+            LLUUID key = new LLUUID();
+            if (LLUUID.TryParse(id,out key))
+            {
+                SceneObjectPart obj = new SceneObjectPart();
+                obj = World.GetSceneObjectPart(World.Entities[key].LocalId);
+                if (obj.OwnerID == World.GetLandOwner(obj.AbsolutePosition.X, obj.AbsolutePosition.Y))
+                {
+                    return 1;
+                }
+                else
+                {
+                    return 0;
+                }
+            }
+            else
+            {
+                return 0;
+            }
+        }
+
+        public string llGetLandOwnerAt(LSL_Types.Vector3 pos)
+        {
+            m_host.AddScriptLPS(1);
+            return World.GetLandOwner((float)pos.x, (float)pos.y).ToString();
+        }
+
+        public LSL_Types.Vector3 llGetAgentSize(string id)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetAgentSize");
+            return new LSL_Types.Vector3();
+        }
+
+        public LSL_Types.LSLInteger llSameGroup(string agent)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSameGroup");
+            return 0;
+        }
+
+        public void llUnSit(string id)
+        {
+            m_host.AddScriptLPS(1);
+
+            LLUUID key = new LLUUID();
+            if (LLUUID.TryParse(id, out key))
+            {
+                ScenePresence av = World.GetScenePresence(key);
+
+                if (av != null)
+                {
+                    if (llAvatarOnSitTarget() == id)
+                    {
+                        // if the avatar is sitting on this object, then
+                        // we can unsit them.  We don't want random scripts unsitting random people
+                        // Lets avoid the popcorn avatar scenario.
+                        av.StandUp();
+                    }
+                    else
+                    {
+                        // If the object owner also owns the parcel
+                        // or
+                        // if the land is group owned and the object is group owned by the same group
+                        // or
+                        // if the object is owned by a person with estate access.
+
+                        ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y);
+                        if (parcel != null)
+                        {
+                            if (m_host.ObjectOwner == parcel.landData.ownerID ||
+                                (m_host.OwnerID == m_host.GroupID && m_host.GroupID == parcel.landData.groupID
+                                && parcel.landData.isGroupOwned) || World.ExternalChecks.ExternalChecksCanBeGodLike(m_host.OwnerID))
+                            {
+                                av.StandUp();
+                            }
+                        }
+                    }
+                }
+
+            }
+
+        }
+
+        public LSL_Types.Vector3 llGroundSlope(LSL_Types.Vector3 offset)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGroundSlope");
+            return new LSL_Types.Vector3();
+        }
+
+        public LSL_Types.Vector3 llGroundNormal(LSL_Types.Vector3 offset)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGroundNormal");
+            return new LSL_Types.Vector3();
+        }
+
+        public LSL_Types.Vector3 llGroundContour(LSL_Types.Vector3 offset)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGroundContour");
+            return new LSL_Types.Vector3();
+        }
+
+        public LSL_Types.LSLInteger llGetAttached()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetAttached");
+            return 0;
+        }
+
+        public LSL_Types.LSLInteger llGetFreeMemory()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetFreeMemory");
+            return 0;
+        }
+
+        public string llGetRegionName()
+        {
+            m_host.AddScriptLPS(1);
+            return World.RegionInfo.RegionName;
+        }
+
+        public double llGetRegionTimeDilation()
+        {
+            m_host.AddScriptLPS(1);
+            return (double)World.TimeDilation;
+        }
+
+        public double llGetRegionFPS()
+        {
+            m_host.AddScriptLPS(1);
+            //TODO: return actual FPS
+            return 10.0f;
+        }
+
+        /* particle system rules should be coming into this routine as doubles, that is
+        rule[0] should be an integer from this list and rule[1] should be the arg
+        for the same integer. wiki.secondlife.com has most of this mapping, but some
+        came from http://www.caligari-designs.com/p4u2
+
+        We iterate through the list for 'Count' elements, incrementing by two for each
+        iteration and set the members of Primitive.ParticleSystem, one at a time.
+        */
+
+        public enum PrimitiveRule : int
+        {
+            PSYS_PART_FLAGS = 0,
+            PSYS_PART_START_COLOR = 1,
+            PSYS_PART_START_ALPHA = 2,
+            PSYS_PART_END_COLOR = 3,
+            PSYS_PART_END_ALPHA = 4,
+            PSYS_PART_START_SCALE = 5,
+            PSYS_PART_END_SCALE = 6,
+            PSYS_PART_MAX_AGE = 7,
+            PSYS_SRC_ACCEL = 8,
+            PSYS_SRC_PATTERN = 9,
+            PSYS_SRC_TEXTURE = 12,
+            PSYS_SRC_BURST_RATE = 13,
+            PSYS_SRC_BURST_PART_COUNT = 15,
+            PSYS_SRC_BURST_RADIUS = 16,
+            PSYS_SRC_BURST_SPEED_MIN = 17,
+            PSYS_SRC_BURST_SPEED_MAX = 18,
+            PSYS_SRC_MAX_AGE = 19,
+            PSYS_SRC_TARGET_KEY = 20,
+            PSYS_SRC_OMEGA = 21,
+            PSYS_SRC_ANGLE_BEGIN = 22,
+            PSYS_SRC_ANGLE_END = 23
+        }
+
+        internal Primitive.ParticleSystem.ParticleDataFlags ConvertUINTtoFlags(uint flags)
+        {
+            Primitive.ParticleSystem.ParticleDataFlags returnval = Primitive.ParticleSystem.ParticleDataFlags.None;
+
+            return returnval;
+        }
+
+
+        public void llParticleSystem(LSL_Types.list rules)
+        {
+            m_host.AddScriptLPS(1);
+            Primitive.ParticleSystem prules = new Primitive.ParticleSystem();
+            LSL_Types.Vector3 tempv = new LSL_Types.Vector3();
+
+            float tempf = 0;
+
+            for (int i = 0; i < rules.Length; i += 2)
+            {
+                switch ((int)rules.Data[i])
+                {
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_PART_FLAGS:
+                        prules.PartDataFlags = (Primitive.ParticleSystem.ParticleDataFlags)((uint)Convert.ToInt32(rules.Data[i + 1].ToString()));
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_PART_START_COLOR:
+                        tempv = (LSL_Types.Vector3)rules.Data[i + 1];
+                        prules.PartStartColor.R = (float)tempv.x;
+                        prules.PartStartColor.G = (float)tempv.y;
+                        prules.PartStartColor.B = (float)tempv.z;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_PART_START_ALPHA:
+                        tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
+                        prules.PartStartColor.A = (float)tempf;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_PART_END_COLOR:
+                        tempv = (LSL_Types.Vector3)rules.Data[i + 1];
+                        //prules.PartEndColor = new LLColor(tempv.x,tempv.y,tempv.z,1);
+
+                        prules.PartEndColor.R = (float)tempv.x;
+                        prules.PartEndColor.G = (float)tempv.y;
+                        prules.PartEndColor.B = (float)tempv.z;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_PART_END_ALPHA:
+                        tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
+                        prules.PartEndColor.A = (float)tempf;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_PART_START_SCALE:
+                        tempv = (LSL_Types.Vector3)rules.Data[i + 1];
+                        prules.PartStartScaleX = (float)tempv.x;
+                        prules.PartStartScaleY = (float)tempv.y;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_PART_END_SCALE:
+                        tempv = (LSL_Types.Vector3)rules.Data[i + 1];
+                        prules.PartEndScaleX = (float)tempv.x;
+                        prules.PartEndScaleY = (float)tempv.y;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_PART_MAX_AGE:
+                        tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
+                        prules.PartMaxAge = (float)tempf;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_ACCEL:
+                        tempv = (LSL_Types.Vector3)rules.Data[i + 1];
+                        prules.PartAcceleration.X = (float)tempv.x;
+                        prules.PartAcceleration.Y = (float)tempv.y;
+                        prules.PartAcceleration.Z = (float)tempv.z;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_PATTERN:
+                        int tmpi = int.Parse(rules.Data[i + 1].ToString());
+                        prules.Pattern = (Primitive.ParticleSystem.SourcePattern)tmpi;
+                        break;
+
+                    // Xantor 03-May-2008
+                    // Wiki:    PSYS_SRC_TEXTURE      string      inventory item name or key of the particle texture
+                    //          "" = default texture.
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_TEXTURE:
+                        LLUUID tkey = LLUUID.Zero;
+
+                        // if we can parse the string as a key, use it.
+                        if (LLUUID.TryParse(rules.Data[i + 1].ToString(), out tkey))
+                        {
+                            prules.Texture = tkey;
+                        }
+                        // else try to locate the name in inventory of object. found returns key,
+                        // not found returns LLUUID.Zero which will translate to the default particle texture
+                        else
+                        {
+                            prules.Texture =  InventoryKey(rules.Data[i+1].ToString());
+                        }
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_BURST_RATE:
+                        tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
+                        prules.BurstRate = (float)tempf;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_BURST_PART_COUNT:
+                        prules.BurstPartCount = (byte)Convert.ToByte(rules.Data[i + 1].ToString());
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_BURST_RADIUS:
+                        tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
+                        prules.BurstRadius = (float)tempf;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_BURST_SPEED_MIN:
+                        tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
+                        prules.BurstSpeedMin = (float)tempf;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_BURST_SPEED_MAX:
+                        tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
+                        prules.BurstSpeedMax = (float)tempf;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_MAX_AGE:
+                        tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
+                        prules.MaxAge = (float)tempf;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_TARGET_KEY:
+                        LLUUID key = LLUUID.Zero;
+                        if (LLUUID.TryParse(rules.Data[i + 1].ToString(), out key))
+                        {
+                            prules.Target = key;
+                        }
+                        else
+                        {
+                            prules.Target = m_host.UUID;
+                        }
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_OMEGA:
+                        // AL: This is an assumption, since it is the only thing that would match.
+                        tempv = (LSL_Types.Vector3)rules.Data[i + 1];
+                        prules.AngularVelocity.X = (float)tempv.x;
+                        prules.AngularVelocity.Y = (float)tempv.y;
+                        prules.AngularVelocity.Z = (float)tempv.z;
+                        //cast??                    prules.MaxAge = (float)rules[i + 1];
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_ANGLE_BEGIN:
+                        tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
+                        prules.InnerAngle = (float)tempf;
+                        break;
+
+                    case (int)BuiltIn_Commands_BaseClass.PSYS_SRC_ANGLE_END:
+                        tempf = Convert.ToSingle(rules.Data[i + 1].ToString());
+                        prules.OuterAngle = (float)tempf;
+                        break;
+                }
+
+            }
+            prules.CRC = 1;
+
+            m_host.AddNewParticleSystem(prules);
+            m_host.SendFullUpdateToAllClients();
+        }
+
+        public void llGroundRepel(double height, int water, double tau)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGroundRepel");
+        }
+
+        public void llGiveInventoryList(string destination, string category, LSL_Types.list inventory)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGiveInventoryList");
+        }
+
+        public void llSetVehicleType(int type)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetVehicleType");
+        }
+
+        public void llSetVehicledoubleParam(int param, double value)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetVehicledoubleParam");
+        }
+
+        public void llSetVehicleFloatParam(int param, float value)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetVehicleFloatParam");
+        }
+
+        public void llSetVehicleVectorParam(int param, LSL_Types.Vector3 vec)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetVehicleVectorParam");
+        }
+
+        public void llSetVehicleRotationParam(int param, LSL_Types.Quaternion rot)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetVehicleRotationParam");
+        }
+
+        public void llSetVehicleFlags(int flags)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetVehicleFlags");
+        }
+
+        public void llRemoveVehicleFlags(int flags)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llRemoveVehicleFlags");
+        }
+
+        public void llSitTarget(LSL_Types.Vector3 offset, LSL_Types.Quaternion rot)
+        {
+            m_host.AddScriptLPS(1);
+            // LSL quaternions can normalize to 0, normal Quaternions can't.
+            if (rot.s == 0 && rot.x == 0 && rot.y == 0 && rot.z == 0)
+                rot.z = 1; // ZERO_ROTATION = 0,0,0,1
+
+            m_host.SetSitTarget(new Vector3((float)offset.x, (float)offset.y, (float)offset.z), new Quaternion((float)rot.s, (float)rot.x, (float)rot.y, (float)rot.z));
+        }
+
+        public string llAvatarOnSitTarget()
+        {
+            m_host.AddScriptLPS(1);
+            return m_host.GetAvatarOnSitTarget().ToString();
+            //LLUUID AVID = m_host.GetAvatarOnSitTarget();
+
+            //if (AVID != LLUUID.Zero)
+            //    return AVID.ToString();
+            //else
+            //    return String.Empty;
+        }
+
+        public void llAddToLandPassList(string avatar, double hours)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID key;
+            LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
+            if (land.ownerID == m_host.OwnerID)
+            {
+                ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
+                if (LLUUID.TryParse(avatar, out key))
+                {
+                    entry.AgentID = key;
+                    entry.Flags = ParcelManager.AccessList.Access;
+                    entry.Time = DateTime.Now.AddHours(hours);
+                    land.parcelAccessList.Add(entry);
+                }
+            }
+        }
+
+        public void llSetTouchText(string text)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.TouchName = text;
+        }
+
+        public void llSetSitText(string text)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.SitName = text;
+        }
+
+        public void llSetCameraEyeOffset(LSL_Types.Vector3 offset)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetCameraEyeOffset");
+        }
+
+        public void llSetCameraAtOffset(LSL_Types.Vector3 offset)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetCameraAtOffset");
+        }
+
+        public string llDumpList2String(LSL_Types.list src, string seperator)
+        {
+            m_host.AddScriptLPS(1);
+            if (src.Length == 0)
+            {
+                return String.Empty;
+            }
+            string ret = String.Empty;
+            foreach (object o in src.Data)
+            {
+                ret = ret + o.ToString() + seperator;
+            }
+            ret = ret.Substring(0, ret.Length - seperator.Length);
+            return ret;
+        }
+
+        public LSL_Types.LSLInteger llScriptDanger(LSL_Types.Vector3 pos)
+        {
+            m_host.AddScriptLPS(1);
+            bool result = World.scriptDanger(m_host.LocalId, new LLVector3((float)pos.x, (float)pos.y, (float)pos.z));
+            if (result)
+            {
+                return 1;
+            }
+            else
+            {
+                return 0;
+            }
+
+        }
+
+        public void llDialog(string avatar, string message, LSL_Types.list buttons, int chat_channel)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID av = new LLUUID();
+            if (!LLUUID.TryParse(avatar,out av))
+            {
+                LSLError("First parameter to llDialog needs to be a key");
+                return;
+            }
+            if (buttons.Length > 12)
+            {
+                LSLError("No more than 12 buttons can be shown");
+                return;
+            }
+            string[] buts = new string[buttons.Length];
+            for (int i = 0; i < buttons.Length; i++)
+            {
+                if (buttons.Data[i].ToString() == String.Empty)
+                {
+                    LSLError("button label cannot be blank");
+                    return;
+                }
+                if (buttons.Data[i].ToString().Length > 24)
+                {
+                    LSLError("button label cannot be longer than 24 characters");
+                    return;
+                }
+                buts[i] = buttons.Data[i].ToString();
+            }
+            World.SendDialogToUser(av, m_host.Name, m_host.UUID, m_host.OwnerID, message, new LLUUID("00000000-0000-2222-3333-100000001000"), chat_channel, buts);
+        }
+
+        public void llVolumeDetect(int detect)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llVolumeDetect");
+        }
+
+        /// <summary>
+        /// Reset the named script. The script must be present
+        /// in the same prim.
+        /// </summary>
+
+        public void llResetOtherScript(string name)
+        {
+            LLUUID item;
+
+            m_host.AddScriptLPS(1);
+
+            if ((item = ScriptByName(name)) != LLUUID.Zero)
+                m_ScriptEngine.ResetScript(item);
+            else
+                ShoutError("llResetOtherScript: script "+name+" not found");
+        }
+
+        public LSL_Types.LSLInteger llGetScriptState(string name)
+        {
+            LLUUID item;
+
+            m_host.AddScriptLPS(1);
+
+            if ((item = ScriptByName(name)) != LLUUID.Zero)
+            {
+                return m_ScriptEngine.GetScriptState(item) ?1:0;
+            }
+
+            ShoutError("llGetScriptState: script "+name+" not found");
+
+            // If we didn't find it, then it's safe to
+            // assume it is not running.
+
+            return 0;
+        }
+
+        public void llRemoteLoadScript()
+        {
+            m_host.AddScriptLPS(1);
+            Deprecated("llRemoteLoadScript");
+        }
+
+        public void llSetRemoteScriptAccessPin(int pin)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetRemoteScriptAccessPin");
+        }
+
+        public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llRemoteLoadScriptPin");
+        }
+
+        //  remote_data(integer type, key channel, key message_id, string sender, integer ival, string sval)
+        // Not sure where these constants should live:
+        // REMOTE_DATA_CHANNEL = 1
+        // REMOTE_DATA_REQUEST = 2
+        // REMOTE_DATA_REPLY = 3
+        public void llOpenRemoteDataChannel()
+        {
+            m_host.AddScriptLPS(1);
+            IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
+            if (xmlrpcMod.IsEnabled())
+            {
+                LLUUID channelID = xmlrpcMod.OpenXMLRPCChannel(m_localID, m_itemID, LLUUID.Zero);
+                object[] resobj = new object[] { new LSL_Types.LSLInteger(1), new LSL_Types.LSLString(channelID.ToString()), new LSL_Types.LSLString(LLUUID.Zero.ToString()), new LSL_Types.LSLString(String.Empty), new LSL_Types.LSLInteger(0), new LSL_Types.LSLString(String.Empty) };
+                m_ScriptEngine.PostScriptEvent(m_itemID, new XEventParams(
+                        "remote_data", resobj,
+                        new XDetectParams[0]));
+            }
+        }
+
+        public string llSendRemoteData(string channel, string dest, int idata, string sdata)
+        {
+            m_host.AddScriptLPS(1);
+            IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
+            return (xmlrpcMod.SendRemoteData(m_localID, m_itemID, channel, dest, idata, sdata)).ToString();
+        }
+
+        public void llRemoteDataReply(string channel, string message_id, string sdata, int idata)
+        {
+            m_host.AddScriptLPS(1);
+            IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
+            xmlrpcMod.RemoteDataReply(channel, message_id, sdata, idata);
+        }
+
+        public void llCloseRemoteDataChannel(string channel)
+        {
+            m_host.AddScriptLPS(1);
+            IXMLRPC xmlrpcMod = m_ScriptEngine.World.RequestModuleInterface<IXMLRPC>();
+            xmlrpcMod.CloseXMLRPCChannel(channel);
+        }
+
+        public string llMD5String(string src, int nonce)
+        {
+            m_host.AddScriptLPS(1);
+            return Util.Md5Hash(src + ":" + nonce.ToString());
+        }
+
+        public void llSetPrimitiveParams(LSL_Types.list rules)
+        {
+            llSetLinkPrimitiveParams(m_host.LinkNum+1, rules);
+        }
+
+        public void llSetLinkPrimitiveParams(int linknumber, LSL_Types.list rules)
+        {
+            m_host.AddScriptLPS(1);
+
+            SceneObjectPart part=null;
+
+            if (m_host.LinkNum+1 != linknumber)
+            {
+                foreach (SceneObjectPart partInst in m_host.ParentGroup.GetParts())
+                {
+                    if ((partInst.LinkNum + 1) == linknumber)
+                    {
+                        part = partInst;
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                part = m_host;
+            }
+
+            if (part == null)
+                return;
+
+            int idx = 0;
+
+            while (idx < rules.Length)
+            {
+                int code = Convert.ToInt32(rules.Data[idx++]);
+
+                int remain = rules.Length - idx;
+
+                int face;
+                LSL_Types.Vector3 v;
+
+                switch (code)
+                {
+                    case 6: // PRIM_POSITION
+                        if (remain < 1)
+                            return;
+
+                        v=new LSL_Types.Vector3(rules.Data[idx++].ToString());
+                        SetPos(part, v);
+
+                        break;
+
+                    case 8: // PRIM_ROTATION
+                        if (remain < 1)
+                            return;
+
+                        LSL_Types.Quaternion q = new LSL_Types.Quaternion(rules.Data[idx++].ToString());
+                        SetRot(part, q);
+
+                        break;
+
+                    case 17: // PRIM_TEXTURE
+                        if (remain < 5)
+                            return;
+
+                        face=Convert.ToInt32(rules.Data[idx++]);
+                        string tex=rules.Data[idx++].ToString();
+                        LSL_Types.Vector3 repeats=new LSL_Types.Vector3(rules.Data[idx++].ToString());
+                        LSL_Types.Vector3 offsets=new LSL_Types.Vector3(rules.Data[idx++].ToString());
+                        double rotation=Convert.ToDouble(rules.Data[idx++]);
+
+                        SetTexture(part, tex, face);
+                        ScaleTexture(part, repeats.x, repeats.y, face);
+                        OffsetTexture(part, offsets.x, offsets.y, face);
+                        RotateTexture(part, rotation, face);
+
+                        break;
+
+                    case 18: // PRIM_COLOR
+                        if (remain < 3)
+                            return;
+
+                        face=Convert.ToInt32(rules.Data[idx++]);
+                        LSL_Types.Vector3 color=new LSL_Types.Vector3(rules.Data[idx++].ToString());
+                        double alpha=Convert.ToDouble(rules.Data[idx++]);
+
+                        SetColor(part, color, face);
+                        SetAlpha(part, alpha, face);
+
+                        break;
+
+                    case 7: // PRIM_SIZE
+                        if (remain < 1)
+                            return;
+
+                        v=new LSL_Types.Vector3(rules.Data[idx++].ToString());
+                        SetScale(part, v);
+
+                        break;
+                }
+            }
+        }
+
+        public string llStringToBase64(string str)
+        {
+            m_host.AddScriptLPS(1);
+            try
+            {
+                byte[] encData_byte = new byte[str.Length];
+                encData_byte = Encoding.UTF8.GetBytes(str);
+                string encodedData = Convert.ToBase64String(encData_byte);
+                return encodedData;
+            }
+            catch (Exception e)
+            {
+                throw new Exception("Error in base64Encode" + e.Message);
+            }
+        }
+
+        public string llBase64ToString(string str)
+        {
+            m_host.AddScriptLPS(1);
+            UTF8Encoding encoder = new UTF8Encoding();
+            Decoder utf8Decode = encoder.GetDecoder();
+            try
+            {
+                byte[] todecode_byte = Convert.FromBase64String(str);
+                int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
+                char[] decoded_char = new char[charCount];
+                utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
+                string result = new String(decoded_char);
+                return result;
+            }
+            catch (Exception e)
+            {
+                throw new Exception("Error in base64Decode" + e.Message);
+            }
+        }
+
+        public void llXorBase64Strings()
+        {
+            m_host.AddScriptLPS(1);
+            Deprecated("llXorBase64Strings");
+        }
+
+        public void llRemoteDataSetRegion()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llRemoteDataSetRegion");
+        }
+
+        public double llLog10(double val)
+        {
+            m_host.AddScriptLPS(1);
+            return (double)Math.Log10(val);
+        }
+
+        public double llLog(double val)
+        {
+            m_host.AddScriptLPS(1);
+            return (double)Math.Log(val);
+        }
+
+        public LSL_Types.list llGetAnimationList(string id)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetAnimationList");
+            return new LSL_Types.list();
+        }
+
+        public void llSetParcelMusicURL(string url)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID landowner = World.GetLandOwner(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
+            if (landowner == LLUUID.Zero)
+            {
+                return;
+            }
+            if (landowner != m_host.ObjectOwner)
+            {
+                return;
+            }
+            World.SetLandMusicURL(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, url);
+        }
+
+        public void osSetParcelMediaURL(string url)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID landowner = World.GetLandOwner(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
+
+            if (landowner == LLUUID.Zero)
+            {
+                return;
+            }
+
+            if (landowner != m_host.ObjectOwner)
+            {
+                return;
+            }
+
+            World.SetLandMediaURL(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, url);
+        }
+
+        public LSL_Types.Vector3 llGetRootPosition()
+        {
+            m_host.AddScriptLPS(1);
+            return new LSL_Types.Vector3(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y, m_host.ParentGroup.AbsolutePosition.Z);
+        }
+
+        public LSL_Types.Quaternion llGetRootRotation()
+        {
+            m_host.AddScriptLPS(1);
+            return new LSL_Types.Quaternion(m_host.ParentGroup.GroupRotation.X, m_host.ParentGroup.GroupRotation.Y, m_host.ParentGroup.GroupRotation.Z, m_host.ParentGroup.GroupRotation.W);
+        }
+
+        public string llGetObjectDesc()
+        {
+            return m_host.Description!=null?m_host.Description:String.Empty;
+        }
+
+        public void llSetObjectDesc(string desc)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.Description = desc!=null?desc:String.Empty;
+        }
+
+        public string llGetCreator()
+        {
+            m_host.AddScriptLPS(1);
+            return m_host.ObjectCreator.ToString();
+        }
+
+        public string llGetTimestamp()
+        {
+            m_host.AddScriptLPS(1);
+            return DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffffffZ");
+        }
+
+        public void llSetLinkAlpha(int linknumber, double alpha, int face)
+        {
+            m_host.AddScriptLPS(1);
+            SceneObjectPart part = m_host.ParentGroup.GetLinkNumPart(linknumber);
+            if (linknumber > -1)
+            {
+                LLObject.TextureEntry tex = part.Shape.Textures;
+                LLColor texcolor;
+                if (face > -1)
+                {
+                    texcolor = tex.CreateFace((uint)face).RGBA;
+                    texcolor.A = (float)Math.Abs(alpha - 1);
+                    tex.FaceTextures[face].RGBA = texcolor;
+                    part.UpdateTexture(tex);
+                    return;
+                }
+                else if (face == -1)
+                {
+                    texcolor = tex.DefaultTexture.RGBA;
+                    texcolor.A = (float)Math.Abs(alpha - 1);
+                    tex.DefaultTexture.RGBA = texcolor;
+                    for (uint i = 0; i < 32; i++)
+                    {
+                        if (tex.FaceTextures[i] != null)
+                        {
+                            texcolor = tex.FaceTextures[i].RGBA;
+                            texcolor.A = (float)Math.Abs(alpha - 1);
+                            tex.FaceTextures[i].RGBA = texcolor;
+                        }
+                    }
+                    texcolor = tex.DefaultTexture.RGBA;
+                    texcolor.A = (float)Math.Abs(alpha - 1);
+                    tex.DefaultTexture.RGBA = texcolor;
+                    part.UpdateTexture(tex);
+                    return;
+                }
+                return;
+            }
+            else if (linknumber == -1)
+            {
+                int num = m_host.ParentGroup.PrimCount;
+                for (int w = 0; w < num; w++)
+                {
+                    linknumber = w;
+                    part = m_host.ParentGroup.GetLinkNumPart(linknumber);
+                    LLObject.TextureEntry tex = part.Shape.Textures;
+                    LLColor texcolor;
+                    if (face > -1)
+                    {
+                        texcolor = tex.CreateFace((uint)face).RGBA;
+                        texcolor.A = (float)Math.Abs(alpha - 1);
+                        tex.FaceTextures[face].RGBA = texcolor;
+                        part.UpdateTexture(tex);
+                    }
+                    else if (face == -1)
+                    {
+                        texcolor = tex.DefaultTexture.RGBA;
+                        texcolor.A = (float)Math.Abs(alpha - 1);
+                        tex.DefaultTexture.RGBA = texcolor;
+                        for (uint i = 0; i < 32; i++)
+                        {
+                            if (tex.FaceTextures[i] != null)
+                            {
+                                texcolor = tex.FaceTextures[i].RGBA;
+                                texcolor.A = (float)Math.Abs(alpha - 1);
+                                tex.FaceTextures[i].RGBA = texcolor;
+                            }
+                        }
+                        texcolor = tex.DefaultTexture.RGBA;
+                        texcolor.A = (float)Math.Abs(alpha - 1);
+                        tex.DefaultTexture.RGBA = texcolor;
+                        part.UpdateTexture(tex);
+                    }
+                }
+                return;
+            }
+        }
+
+        public LSL_Types.LSLInteger llGetNumberOfPrims()
+        {
+            m_host.AddScriptLPS(1);
+            return m_host.ParentGroup.PrimCount;
+        }
+
+        public LSL_Types.list llGetBoundingBox(string obj)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetBoundingBox");
+            return new LSL_Types.list();
+        }
+
+        public LSL_Types.Vector3 llGetGeometricCenter()
+        {
+            return new LSL_Types.Vector3(m_host.GetGeometricCenter().X, m_host.GetGeometricCenter().Y, m_host.GetGeometricCenter().Z);
+        }
+
+        public LSL_Types.list llGetPrimitiveParams(LSL_Types.list rules)
+        {
+            m_host.AddScriptLPS(1);
+
+            LSL_Types.list res = new LSL_Types.list();
+            int idx=0;
+            while (idx < rules.Length)
+            {
+                int code=Convert.ToInt32(rules.Data[idx++]);
+                int remain=rules.Length-idx;
+
+                switch (code)
+                {
+                    case 2: // PRIM_MATERIAL
+                        res.Add(new LSL_Types.LSLInteger(m_host.Material));
+                        break;
+
+                    case 3: // PRIM_PHYSICS
+                        if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.Physics) != 0)
+                            res.Add(new LSL_Types.LSLInteger(1));
+                        else
+                            res.Add(new LSL_Types.LSLInteger(0));
+                        break;
+
+                    case 4: // PRIM_TEMP_ON_REZ
+                        if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.TemporaryOnRez) != 0)
+                            res.Add(new LSL_Types.LSLInteger(1));
+                        else
+                            res.Add(new LSL_Types.LSLInteger(0));
+                        break;
+
+                    case 5: // PRIM_PHANTOM
+                        if ((m_host.GetEffectiveObjectFlags() & (uint)LLObject.ObjectFlags.Phantom) != 0)
+                            res.Add(new LSL_Types.LSLInteger(1));
+                        else
+                            res.Add(new LSL_Types.LSLInteger(0));
+                        break;
+
+                    case 6: // PRIM_POSITION
+                        res.Add(new LSL_Types.Vector3(m_host.AbsolutePosition.X,
+                                                      m_host.AbsolutePosition.Y,
+                                                      m_host.AbsolutePosition.Z));
+                        break;
+
+                    case 7: // PRIM_SIZE
+                        res.Add(new LSL_Types.Vector3(m_host.Scale.X,
+                                                      m_host.Scale.Y,
+                                                      m_host.Scale.Z));
+                        break;
+
+                    case 8: // PRIM_ROTATION
+                        res.Add(new LSL_Types.Quaternion(m_host.RotationOffset.X,
+                                                         m_host.RotationOffset.Y,
+                                                         m_host.RotationOffset.Z,
+                                                         m_host.RotationOffset.W));
+                        break;
+
+                    case 9: // PRIM_TYPE
+                        // TODO--------------
+                        res.Add(new LSL_Types.LSLInteger(0));
+                        break;
+
+                    case 17: // PRIM_TEXTURE
+                        if (remain < 1)
+                            return res;
+
+                        int face=Convert.ToInt32(rules.Data[idx++]);
+                        if (face == -1)
+                            face = 0;
+
+                        LLObject.TextureEntry tex = m_host.Shape.Textures;
+                        LLObject.TextureEntryFace texface = tex.GetFace((uint)face);
+
+                        res.Add(new LSL_Types.LSLString(texface.TextureID.ToString()));
+                        res.Add(new LSL_Types.Vector3(texface.RepeatU,
+                                                      texface.RepeatV,
+                                                      0));
+                        res.Add(new LSL_Types.Vector3(texface.OffsetU,
+                                                      texface.OffsetV,
+                                                      0));
+                        res.Add(new LSL_Types.LSLFloat(texface.Rotation));
+                        break;
+
+                    case 18: // PRIM_COLOR
+                        if (remain < 1)
+                            return res;
+
+                        face=Convert.ToInt32(rules.Data[idx++]);
+
+                        tex = m_host.Shape.Textures;
+                        LLColor texcolor;
+                        if (face == -1) // TMP: Until we can determine number of sides, ALL_SIDES (-1) will return default color
+                            texcolor = tex.DefaultTexture.RGBA;
+                        else
+                            texcolor = tex.GetFace((uint)face).RGBA;
+                        res.Add(new LSL_Types.Vector3((255 - (texcolor.R * 255)) / 255,
+                                                      (255 - (texcolor.G * 255)) / 255,
+                                                      (255 - (texcolor.B * 255)) / 255));
+                        res.Add(new LSL_Types.LSLFloat((texcolor.A * 255) / 255));
+                        break;
+
+                    case 19: // PRIM_BUMP_SHINY
+                        // TODO--------------
+                        if (remain < 1)
+                            return res;
+
+                        face=Convert.ToInt32(rules.Data[idx++]);
+
+                        res.Add(new LSL_Types.LSLInteger(0));
+                        res.Add(new LSL_Types.LSLInteger(0));
+                        break;
+
+                    case 20: // PRIM_FULLBRIGHT
+                        // TODO--------------
+                        if (remain < 1)
+                            return res;
+
+                        face=Convert.ToInt32(rules.Data[idx++]);
+
+                        res.Add(new LSL_Types.LSLInteger(0));
+                        break;
+
+                    case 21: // PRIM_FLEXIBLE
+                        PrimitiveBaseShape shape = m_host.Shape;
+
+                        if (shape.FlexiEntry)
+                            res.Add(new LSL_Types.LSLInteger(1));              // active
+                        else
+                            res.Add(new LSL_Types.LSLInteger(0));
+                        res.Add(new LSL_Types.LSLInteger(shape.FlexiSoftness));// softness
+                        res.Add(new LSL_Types.LSLFloat(shape.FlexiGravity));   // gravity
+                        res.Add(new LSL_Types.LSLFloat(shape.FlexiDrag));      // friction
+                        res.Add(new LSL_Types.LSLFloat(shape.FlexiWind));      // wind
+                        res.Add(new LSL_Types.LSLFloat(shape.FlexiTension));   // tension
+                        res.Add(new LSL_Types.Vector3(shape.FlexiForceX,       // force
+                                                      shape.FlexiForceY,
+                                                      shape.FlexiForceZ));
+                        break;
+
+                    case 22: // PRIM_TEXGEN
+                        // TODO--------------
+                        // (PRIM_TEXGEN_DEFAULT, PRIM_TEXGEN_PLANAR)
+                        if (remain < 1)
+                            return res;
+
+                        face=Convert.ToInt32(rules.Data[idx++]);
+
+                        res.Add(new LSL_Types.LSLInteger(0));
+                        break;
+
+                    case 23: // PRIM_POINT_LIGHT:
+                        shape = m_host.Shape;
+
+                        if (shape.LightEntry)
+                            res.Add(new LSL_Types.LSLInteger(1));              // active
+                        else
+                            res.Add(new LSL_Types.LSLInteger(0));
+                        res.Add(new LSL_Types.Vector3(shape.LightColorR,       // color
+                                                      shape.LightColorG,
+                                                      shape.LightColorB));
+                        res.Add(new LSL_Types.LSLFloat(shape.LightIntensity)); // intensity
+                        res.Add(new LSL_Types.LSLFloat(shape.LightRadius));    // radius
+                        res.Add(new LSL_Types.LSLFloat(shape.LightFalloff));   // falloff
+                        break;
+
+                    case 24: // PRIM_GLOW
+                        // TODO--------------
+                        if (remain < 1)
+                            return res;
+
+                        face=Convert.ToInt32(rules.Data[idx++]);
+
+                        res.Add(new LSL_Types.LSLFloat(0));
+                        break;
+                }
+            }
+            return res;
+        }
+
+        //  <remarks>
+        //  <para>
+        //  The .NET definition of base 64 is:
+        //  <list>
+        //  <item>
+        //  Significant: A-Z a-z 0-9 + -
+        //  </item>
+        //  <item>
+        //  Whitespace: \t \n \r ' '
+        //  </item>
+        //  <item>
+        //  Valueless: =
+        //  </item>
+        //  <item>
+        //  End-of-string: \0 or '=='
+        //  </item>
+        //  </list>
+        //  </para>
+        //  <para>
+        //  Each point in a base-64 string represents
+        //  a 6 bit value. A 32-bit integer can be
+        //  represented using 6 characters (with some
+        //  redundancy).
+        //  </para>
+        //  <para>
+        //  LSL requires a base64 string to be 8
+        //  characters in length. LSL also uses '/'
+        //  rather than '-' (MIME compliant).
+        //  </para>
+        //  <para>
+        //  RFC 1341 used as a reference (as specified
+        //  by the SecondLife Wiki).
+        //  </para>
+        //  <para>
+        //  SL do not record any kind of exception for
+        //  these functions, so the string to integer
+        //  conversion returns '0' if an invalid
+        //  character is encountered during conversion.
+        //  </para>
+        //  <para>
+        //  References
+        //  <list>
+        //  <item>
+        //  http://lslwiki.net/lslwiki/wakka.php?wakka=Base64
+        //  </item>
+        //  <item>
+        //  </item>
+        //  </list>
+        //  </para>
+        //  </remarks>
+
+        //  <summary>
+        //  Table for converting 6-bit integers into
+        //  base-64 characters
+        //  </summary>
+
+        private static readonly char[] i2ctable =
+        {
+            'A','B','C','D','E','F','G','H',
+            'I','J','K','L','M','N','O','P',
+            'Q','R','S','T','U','V','W','X',
+            'Y','Z',
+            'a','b','c','d','e','f','g','h',
+            'i','j','k','l','m','n','o','p',
+            'q','r','s','t','u','v','w','x',
+            'y','z',
+            '0','1','2','3','4','5','6','7',
+            '8','9',
+            '+','/'
+        };
+
+        //  <summary>
+        //  Table for converting base-64 characters
+        //  into 6-bit integers.
+        //  </summary>
+
+        private static readonly int[] c2itable =
+        {
+            -1,-1,-1,-1,-1,-1,-1,-1,    // 0x
+            -1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,    // 1x
+            -1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,    // 2x
+            -1,-1,-1,63,-1,-1,-1,64,
+            53,54,55,56,57,58,59,60,    // 3x
+            61,62,-1,-1,-1,0,-1,-1,
+            -1,1,2,3,4,5,6,7,           // 4x
+            8,9,10,11,12,13,14,15,
+            16,17,18,19,20,21,22,23,    // 5x
+            24,25,26,-1,-1,-1,-1,-1,
+            -1,27,28,29,30,31,32,33,    // 6x
+            34,35,36,37,38,39,40,41,
+            42,43,44,45,46,47,48,49,    // 7x
+            50,51,52,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,    // 8x
+            -1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,    // 9x
+            -1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,    // Ax
+            -1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,    // Bx
+            -1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,    // Cx
+            -1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,    // Dx
+            -1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,    // Ex
+            -1,-1,-1,-1,-1,-1,-1,-1,
+            -1,-1,-1,-1,-1,-1,-1,-1,    // Fx
+            -1,-1,-1,-1,-1,-1,-1,-1
+        };
+
+        //  <summary>
+        //  Converts a 32-bit integer into a Base64
+        //  character string. Base64 character strings
+        //  are always 8 characters long. All iinteger
+        //  values are acceptable.
+        //  </summary>
+        //  <param name="number">
+        //  32-bit integer to be converted.
+        //  </param>
+        //  <returns>
+        //  8 character string. The 1st six characters
+        //  contain the encoded number, the last two
+        //  characters are padded with "=".
+        //  </returns>
+
+        public string llIntegerToBase64(int number)
+        {
+            // uninitialized string
+
+            char[] imdt = new char[8];
+
+            m_host.AddScriptLPS(1);
+
+            // Manually unroll the loop
+
+            imdt[7] = '=';
+            imdt[6] = '=';
+            imdt[5] = i2ctable[number<<4  & 0x3F];
+            imdt[4] = i2ctable[number>>2  & 0x3F];
+            imdt[3] = i2ctable[number>>8  & 0x3F];
+            imdt[2] = i2ctable[number>>14 & 0x3F];
+            imdt[1] = i2ctable[number>>20 & 0x3F];
+            imdt[0] = i2ctable[number>>26 & 0x3F];
+
+            return new string(imdt);
+        }
+
+        //  <summary>
+        //  Converts an eight character base-64 string
+        //  into a 32-bit integer.
+        //  </summary>
+        //  <param name="str">
+        //  8 characters string to be converted. Other
+        //  length strings return zero.
+        //  </param>
+        //  <returns>
+        //  Returns an integer representing the
+        //  encoded value providedint he 1st 6
+        //  characters of the string.
+        //  </returns>
+        //  <remarks>
+        //  This is coded to behave like LSL's
+        //  implementation (I think), based upon the
+        //  information available at the Wiki.
+        //  If more than 8 characters are supplied,
+        //  zero is returned.
+        //  If a NULL string is supplied, zero will
+        //  be returned.
+        //  If fewer than 6 characters are supplied, then
+        //  the answer will reflect a partial
+        //  accumulation.
+        //  <para>
+        //  The 6-bit segments are
+        //  extracted left-to-right in big-endian mode,
+        //  which means that segment 6 only contains the
+        //  two low-order bits of the 32 bit integer as
+        //  its high order 2 bits. A short string therefore
+        //  means loss of low-order information. E.g.
+        //
+        //  |<---------------------- 32-bit integer ----------------------->|<-Pad->|
+        //  |<--Byte 0----->|<--Byte 1----->|<--Byte 2----->|<--Byte 3----->|<-Pad->|
+        //  |3|3|2|2|2|2|2|2|2|2|2|2|1|1|1|1|1|1|1|1|1|1| | | | | | | | | | |P|P|P|P|
+        //  |1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|9|8|7|6|5|4|3|2|1|0|P|P|P|P|
+        //  |  str[0]   |  str[1]   |  str[2]   |  str[3]   |  str[4]   |  str[6]   |
+        //
+        //  </para>
+        //  </remarks>
+
+        public LSL_Types.LSLInteger llBase64ToInteger(string str)
+        {
+            int number = 0;
+            int digit;
+
+            m_host.AddScriptLPS(1);
+
+            //    Require a well-fromed base64 string
+
+            if (str.Length > 8)
+                return 0;
+
+            //    The loop is unrolled in the interests
+            //    of performance and simple necessity.
+            //
+            //    MUST find 6 digits to be well formed
+            //      -1 == invalid
+            //       0 == padding
+
+            if ((digit=c2itable[str[0]])<=0)
+            {
+                return digit<0?(int)0:number;
+            }
+            number += --digit<<26;
+
+            if ((digit=c2itable[str[1]])<=0)
+            {
+                return digit<0?(int)0:number;
+            }
+            number += --digit<<20;
+
+            if ((digit=c2itable[str[2]])<=0)
+            {
+                return digit<0?(int)0:number;
+            }
+            number += --digit<<14;
+
+            if ((digit=c2itable[str[3]])<=0)
+            {
+                return digit<0?(int)0:number;
+            }
+            number += --digit<<8;
+
+            if ((digit=c2itable[str[4]])<=0)
+            {
+                return digit<0?(int)0:number;
+            }
+            number += --digit<<2;
+
+            if ((digit=c2itable[str[5]])<=0)
+            {
+                return digit<0?(int)0:number;
+            }
+            number += --digit>>4;
+
+            // ignore trailing padding
+
+            return number;
+        }
+
+        public double llGetGMTclock()
+        {
+            m_host.AddScriptLPS(1);
+            return DateTime.UtcNow.TimeOfDay.TotalSeconds;
+        }
+
+        public string llGetSimulatorHostname()
+        {
+            m_host.AddScriptLPS(1);
+            return System.Environment.MachineName;
+        }
+
+        public void llSetLocalRot(LSL_Types.Quaternion rot)
+        {
+            m_host.AddScriptLPS(1);
+            m_host.RotationOffset = new LLQuaternion((float)rot.x, (float)rot.y, (float)rot.z, (float)rot.s);
+        }
+
+        //  <summary>
+        //  Scan the string supplied in 'src' and
+        //  tokenize it based upon two sets of
+        //  tokenizers provided in two lists,
+        //  separators and spacers.
+        //  </summary>
+        //
+        //  <remarks>
+        //  Separators demarcate tokens and are
+        //  elided as they are encountered. Spacers
+        //  also demarcate tokens, but are themselves
+        //  retained as tokens.
+        //
+        //  Both separators and spacers may be arbitrarily
+        //  long strings. i.e. ":::".
+        //
+        //  The function returns an ordered list
+        //  representing the tokens found in the supplied
+        //  sources string. If two successive tokenizers
+        //  are encountered, then a NULL entry is added
+        //  to the list.
+        //
+        //  It is a precondition that the source and
+        //  toekizer lisst are non-null. If they are null,
+        //  then a null pointer exception will be thrown
+        //  while their lengths are being determined.
+        //
+        //  A small amount of working memoryis required
+        //  of approximately 8*#tokenizers.
+        //
+        //  There are many ways in which this function
+        //  can be implemented, this implementation is
+        //  fairly naive and assumes that when the
+        //  function is invooked with a short source
+        //  string and/or short lists of tokenizers, then
+        //  performance will not be an issue.
+        //
+        //  In order to minimize the perofrmance
+        //  effects of long strings, or large numbers
+        //  of tokeizers, the function skips as far as
+        //  possible whenever a toekenizer is found,
+        //  and eliminates redundant tokenizers as soon
+        //  as is possible.
+        //
+        //  The implementation tries to avoid any copying
+        //  of arrays or other objects.
+        //  </remarks>
+
+        public LSL_Types.list llParseStringKeepNulls(string src, LSL_Types.list separators, LSL_Types.list spacers)
+        {
+            int         beginning = 0;
+            int         srclen    = src.Length;
+            int         seplen    = separators.Length;
+            object[]    separray  = separators.Data;
+            int         spclen    = spacers.Length;
+            object[]    spcarray  = spacers.Data;
+            int         mlen      = seplen+spclen;
+
+            int[]       offset    = new int[mlen+1];
+            bool[]      active    = new bool[mlen];
+
+            int         best;
+            int         j;
+
+            //    Initial capacity reduces resize cost
+
+            LSL_Types.list tokens = new LSL_Types.list();
+
+            m_host.AddScriptLPS(1);
+
+            //    All entries are initially valid
+
+            for (int i = 0; i < mlen; i++)
+                active[i] = true;
+
+            offset[mlen] = srclen;
+
+            while (beginning < srclen)
+            {
+
+                best = mlen;    // as bad as it gets
+
+                //    Scan for separators
+
+                for (j = 0; j < seplen; j++)
+                {
+                    if (active[j])
+                    {
+                        // scan all of the markers
+                        if ((offset[j] = src.IndexOf((string)separray[j],beginning)) == -1)
+                        {
+                            // not present at all
+                            active[j] = false;
+                        }
+                        else
+                        {
+                            // present and correct
+                            if (offset[j] < offset[best])
+                            {
+                                // closest so far
+                                best = j;
+                                if (offset[best] == beginning)
+                                    break;
+                            }
+                        }
+                    }
+                }
+
+                //    Scan for spacers
+
+                if (offset[best] != beginning)
+                {
+                    for (j = seplen; (j < mlen) && (offset[best] > beginning); j++)
+                    {
+                        if (active[j])
+                        {
+                            // scan all of the markers
+                            if ((offset[j] = src.IndexOf((string)spcarray[j-seplen],beginning)) == -1)
+                            {
+                                // not present at all
+                                active[j] = false;
+                            } else
+                            {
+                                // present and correct
+                                if (offset[j] < offset[best])
+                                {
+                                    // closest so far
+                                    best = j;
+                                }
+                            }
+                        }
+                    }
+                }
+
+                //    This is the normal exit from the scanning loop
+
+                if (best == mlen)
+                {
+                    // no markers were found on this pass
+                    // so we're pretty much done
+                    tokens.Add(src.Substring(beginning, srclen-beginning));
+                    break;
+                }
+
+                //    Otherwise we just add the newly delimited token
+                //    and recalculate where the search should continue.
+
+                tokens.Add(src.Substring(beginning,offset[best]-beginning));
+
+                if (best<seplen)
+                {
+                    beginning = offset[best]+((string)separray[best]).Length;
+                } else
+                {
+                    beginning = offset[best]+((string)spcarray[best-seplen]).Length;
+                    tokens.Add(spcarray[best-seplen]);
+                }
+
+            }
+
+            //    This an awkward an not very intuitive boundary case. If the
+            //    last substring is a tokenizer, then there is an implied trailing
+            //    null list entry. Hopefully the single comparison will not be too
+            //    arduous. Alternatively the 'break' could be replced with a return
+            //    but that's shabby programming.
+
+            if (beginning == srclen)
+            {
+                if (srclen != 0)
+                    tokens.Add("");
+            }
+
+            return tokens;
+        }
+
+        public void llRezAtRoot(string inventory, LSL_Types.Vector3 position, LSL_Types.Vector3 velocity,
+                                LSL_Types.Quaternion rot, int param)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llRezAtRoot");
+        }
+
+        public LSL_Types.LSLInteger llGetObjectPermMask(int mask)
+        {
+            m_host.AddScriptLPS(1);
+
+            int permmask = 0;
+
+            if (mask == BuiltIn_Commands_BaseClass.MASK_BASE)//0
+            {
+                permmask = (int)m_host.BaseMask;
+            }
+
+            else if (mask == BuiltIn_Commands_BaseClass.MASK_OWNER)//1
+            {
+                permmask = (int)m_host.OwnerMask;
+            }
+
+            else if (mask == BuiltIn_Commands_BaseClass.MASK_GROUP)//2
+            {
+                permmask = (int)m_host.GroupMask;
+            }
+
+            else if (mask == BuiltIn_Commands_BaseClass.MASK_EVERYONE)//3
+            {
+                permmask = (int)m_host.EveryoneMask;
+            }
+
+            else if (mask == BuiltIn_Commands_BaseClass.MASK_NEXT)//4
+            {
+                permmask = (int)m_host.NextOwnerMask;
+            }
+
+            return permmask;
+        }
+
+        public void llSetObjectPermMask(int mask, int value)
+        {
+            m_host.AddScriptLPS(1);
+
+            if (mask == BuiltIn_Commands_BaseClass.MASK_BASE)//0
+            {
+                m_host.BaseMask = (uint)value;
+            }
+
+            else if (mask == BuiltIn_Commands_BaseClass.MASK_OWNER)//1
+            {
+                m_host.OwnerMask = (uint)value;
+            }
+
+            else if (mask == BuiltIn_Commands_BaseClass.MASK_GROUP)//2
+            {
+                m_host.GroupMask = (uint)value;
+            }
+
+            else if (mask == BuiltIn_Commands_BaseClass.MASK_EVERYONE)//3
+            {
+                m_host.EveryoneMask = (uint)value;
+            }
+
+            else if (mask == BuiltIn_Commands_BaseClass.MASK_NEXT)//4
+            {
+                m_host.NextOwnerMask = (uint)value;
+            }
+        }
+
+        public LSL_Types.LSLInteger llGetInventoryPermMask(string item, int mask)
+        {
+            m_host.AddScriptLPS(1);
+            foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
+            {
+                if (inv.Value.Name == item)
+                {
+                    switch (mask)
+                    {
+                        case 0:
+                            return (int)inv.Value.BaseMask;
+                        case 1:
+                            return (int)inv.Value.OwnerMask;
+                        case 2:
+                            return (int)inv.Value.GroupMask;
+                        case 3:
+                            return (int)inv.Value.EveryoneMask;
+                        case 4:
+                            return (int)inv.Value.NextOwnerMask;
+                    }
+                }
+            }
+            return -1;
+        }
+
+        public void llSetInventoryPermMask(string item, int mask, int value)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetInventoryPermMask");
+        }
+
+        public string llGetInventoryCreator(string item)
+        {
+            m_host.AddScriptLPS(1);
+            foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
+            {
+                if (inv.Value.Name == item)
+                {
+                    return inv.Value.CreatorID.ToString();
+                }
+            }
+            llSay(0, "No item name '" + item + "'");
+            return String.Empty;
+        }
+
+        public void llOwnerSay(string msg)
+        {
+            m_host.AddScriptLPS(1);
+
+            World.SimChatBroadcast(Helpers.StringToField(msg), ChatTypeEnum.Owner, 0, m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
+//            IWorldComm wComm = m_ScriptEngine.World.RequestModuleInterface<IWorldComm>();
+//            wComm.DeliverMessage(ChatTypeEnum.Owner, 0, m_host.Name, m_host.UUID, msg);
+        }
+
+        public string llRequestSimulatorData(string simulator, int data)
+        {
+try
+{
+            m_host.AddScriptLPS(1);
+
+            string reply = String.Empty;
+
+            RegionInfo info = m_ScriptEngine.World.RequestClosestRegion(simulator);
+
+            switch(data)
+            {
+            case 5: // DATA_SIM_POS
+                if(info == null)
+                    return LLUUID.Zero.ToString();
+                reply = new LSL_Types.Vector3(
+                        info.RegionLocX * Constants.RegionSize,
+                        info.RegionLocY * Constants.RegionSize,
+                        0).ToString();
+                break;
+            case 6: // DATA_SIM_STATUS
+                if(info != null)
+                    reply = "up"; // Duh!
+                else
+                    reply = "unknown";
+                break;
+            case 7: // DATA_SIM_RATING
+                if(info == null)
+                    return LLUUID.Zero.ToString();
+                int access = (int)info.EstateSettings.simAccess;
+                if(access == 21)
+                    reply = "MATURE";
+                else if(access == 13)
+                    reply = "MATURE";
+                else
+                    reply = "UNKNOWN";
+                break;
+            default:
+                return LLUUID.Zero.ToString(); // Raise no event
+            }
+            LLUUID rq = LLUUID.Random();
+
+            LLUUID tid = m_ScriptEngine.m_ASYNCLSLCommandManager.
+                    m_Dataserver.RegisterRequest(m_localID,
+                    m_itemID, rq.ToString());
+
+            m_ScriptEngine.m_ASYNCLSLCommandManager.
+            m_Dataserver.DataserverReply(rq.ToString(), reply);
+
+            return tid.ToString();
+}
+catch(Exception e)
+{
+Console.WriteLine(e.ToString());
+return LLUUID.Zero.ToString();
+}
+        }
+
+        public void llForceMouselook(int mouselook)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llForceMouselook");
+        }
+
+        public double llGetObjectMass(string id)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID key = new LLUUID();
+            if (LLUUID.TryParse(id,out key))
+            {
+                return (double)World.GetSceneObjectPart(World.Entities[key].LocalId).GetMass();
+            }
+            return 0;
+        }
+
+        /// <summary>
+        /// illListReplaceList removes the sub-list defined by the inclusive indices
+        /// start and end and inserts the src list in its place. The inclusive
+        /// nature of the indices means that at least one element must be deleted
+        /// if the indices are within the bounds of the existing list. I.e. 2,2
+        /// will remove the element at index 2 and replace it with the source
+        /// list. Both indices may be negative, with the usual interpretation. An
+        /// interesting case is where end is lower than start. As these indices
+        /// bound the list to be removed, then 0->end, and start->lim are removed
+        /// and the source list is added as a suffix.
+        /// </summary>
+
+        public LSL_Types.list llListReplaceList(LSL_Types.list dest, LSL_Types.list src, int start, int end)
+        {
+
+            LSL_Types.list pref = null;
+
+            m_host.AddScriptLPS(1);
+
+            // Note that although we have normalized, both
+            // indices could still be negative.
+            if (start < 0)
+            {
+                start = start+dest.Length;
+            }
+
+            if (end < 0)
+            {
+                end = end+dest.Length;
+            }
+            // The comventional case, remove a sequence starting with
+            // start and ending with end. And then insert the source
+            // list.
+            if (start <= end)
+            {
+                // If greater than zero, then there is going to be a
+                // surviving prefix. Otherwise the inclusive nature
+                // of the indices mean that we're going to add the
+                // source list as a prefix.
+                if (start > 0)
+                {
+                    pref = dest.GetSublist(0,start-1);
+                    // Only add a suffix if there is something
+                    // beyond the end index (it's inclusive too).
+                    if (end+1 < dest.Length)
+                    {
+                        return pref + src + dest.GetSublist(end+1,-1);
+                    }
+                    else
+                    {
+                        return pref + src;
+                    }
+                }
+                // If start is less than or equal to zero, then
+                // the new list is simply a prefix. We still need to
+                // figure out any necessary surgery to the destination
+                // based upon end. Note that if end exceeds the upper
+                // bound in this case, the entire destination list
+                // is removed.
+                else
+                {
+                    if (end+1 < dest.Length)
+                    {
+                        return src + dest.GetSublist(end+1,-1);
+                    }
+                    else
+                    {
+                        return src;
+                    }
+                }
+            }
+            // Finally, if start > end, we strip away a prefix and
+            // a suffix, to leave the list that sits <between> ens
+            // and start, and then tag on the src list. AT least
+            // that's my interpretation. We can get sublist to do
+            // this for us. Note that one, or both of the indices
+            // might have been negative.
+            else
+            {
+                return dest.GetSublist(end+1,start-1)+src;
+            }
+        }
+
+        public void llLoadURL(string avatar_id, string message, string url)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID avatarId = new LLUUID(avatar_id);
+            m_ScriptEngine.World.SendUrlToUser(avatarId, m_host.Name, m_host.UUID, m_host.ObjectOwner, false, message,
+                                               url);
+        }
+
+        public void llParcelMediaCommandList(LSL_Types.list commandList)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llParcelMediaCommandList");
+        }
+
+        public void llParcelMediaQuery()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llParcelMediaQuery");
+        }
+
+        public LSL_Types.LSLInteger llModPow(int a, int b, int c)
+        {
+            m_host.AddScriptLPS(1);
+            Int64 tmp = 0;
+            Math.DivRem(Convert.ToInt64(Math.Pow(a, b)), c, out tmp);
+            return Convert.ToInt32(tmp);
+        }
+
+        public LSL_Types.LSLInteger llGetInventoryType(string name)
+        {
+            m_host.AddScriptLPS(1);
+            foreach (KeyValuePair<LLUUID, TaskInventoryItem> inv in m_host.TaskInventory)
+            {
+                if (inv.Value.Name == name)
+                {
+                    return inv.Value.InvType;
+                }
+            }
+            return -1;
+        }
+
+        public void llSetPayPrice(int price, LSL_Types.list quick_pay_buttons)
+        {
+            m_host.AddScriptLPS(1);
+
+            if (quick_pay_buttons.Data.Length != 4)
+            {
+                LSLError("List must have 4 elements");
+                return;
+            }
+            m_host.ParentGroup.RootPart.PayPrice[0]=price;
+            m_host.ParentGroup.RootPart.PayPrice[1]=(int)quick_pay_buttons.Data[0];
+            m_host.ParentGroup.RootPart.PayPrice[2]=(int)quick_pay_buttons.Data[1];
+            m_host.ParentGroup.RootPart.PayPrice[3]=(int)quick_pay_buttons.Data[2];
+            m_host.ParentGroup.RootPart.PayPrice[4]=(int)quick_pay_buttons.Data[3];
+        }
+
+        public LSL_Types.Vector3 llGetCameraPos()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetCameraPos");
+            return new LSL_Types.Vector3();
+        }
+
+        public LSL_Types.Quaternion llGetCameraRot()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llGetCameraRot");
+            return new LSL_Types.Quaternion();
+        }
+
+        public void llSetPrimURL()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetPrimURL");
+        }
+
+        public void llRefreshPrimURL()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llRefreshPrimURL");
+        }
+
+        public string llEscapeURL(string url)
+        {
+            m_host.AddScriptLPS(1);
+            try
+            {
+                return Uri.EscapeUriString(url);
+            }
+            catch (Exception ex)
+            {
+                return "llEscapeURL: " + ex.ToString();
+            }
+        }
+
+        public string llUnescapeURL(string url)
+        {
+            m_host.AddScriptLPS(1);
+            try
+            {
+                return Uri.UnescapeDataString(url);
+            }
+            catch (Exception ex)
+            {
+                return "llUnescapeURL: " + ex.ToString();
+            }
+        }
+
+        public void llMapDestination(string simname, LSL_Types.Vector3 pos, LSL_Types.Vector3 look_at)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llMapDestination");
+        }
+
+        public void llAddToLandBanList(string avatar, double hours)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID key;
+            LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
+            if (land.ownerID == m_host.OwnerID)
+            {
+                ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
+                if (LLUUID.TryParse(avatar, out key))
+                {
+                    entry.AgentID = key;
+                    entry.Flags = ParcelManager.AccessList.Ban;
+                    entry.Time = DateTime.Now.AddHours(hours);
+                    land.parcelAccessList.Add(entry);
+                }
+            }
+        }
+
+        public void llRemoveFromLandPassList(string avatar)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID key;
+            LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
+            if (land.ownerID == m_host.OwnerID)
+            {
+                if (LLUUID.TryParse(avatar, out key))
+                {
+                    foreach (ParcelManager.ParcelAccessEntry entry in land.parcelAccessList)
+                    {
+                        if (entry.AgentID == key && entry.Flags == ParcelManager.AccessList.Access)
+                        {
+                            land.parcelAccessList.Remove(entry);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        public void llRemoveFromLandBanList(string avatar)
+        {
+            m_host.AddScriptLPS(1);
+            LLUUID key;
+            LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
+            if (land.ownerID == m_host.OwnerID)
+            {
+                if (LLUUID.TryParse(avatar, out key))
+                {
+                    foreach (ParcelManager.ParcelAccessEntry entry in land.parcelAccessList)
+                    {
+                        if (entry.AgentID == key && entry.Flags == ParcelManager.AccessList.Ban)
+                        {
+                            land.parcelAccessList.Remove(entry);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        public void llSetCameraParams(LSL_Types.list rules)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetCameraParams");
+        }
+
+        public void llClearCameraParams()
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llClearCameraParams");
+        }
+
+        public double llListStatistics(int operation, LSL_Types.list src)
+        {
+            m_host.AddScriptLPS(1);
+            LSL_Types.list nums = LSL_Types.list.ToDoubleList(src);
+            switch (operation)
+            {
+                case BuiltIn_Commands_BaseClass.LIST_STAT_RANGE:
+                    return nums.Range();
+                case BuiltIn_Commands_BaseClass.LIST_STAT_MIN:
+                    return nums.Min();
+                case BuiltIn_Commands_BaseClass.LIST_STAT_MAX:
+                    return nums.Max();
+                case BuiltIn_Commands_BaseClass.LIST_STAT_MEAN:
+                    return nums.Mean();
+                case BuiltIn_Commands_BaseClass.LIST_STAT_MEDIAN:
+                    return nums.Median();
+                case BuiltIn_Commands_BaseClass.LIST_STAT_NUM_COUNT:
+                    return nums.NumericLength();
+                case BuiltIn_Commands_BaseClass.LIST_STAT_STD_DEV:
+                    return nums.StdDev();
+                case BuiltIn_Commands_BaseClass.LIST_STAT_SUM:
+                    return nums.Sum();
+                case BuiltIn_Commands_BaseClass.LIST_STAT_SUM_SQUARES:
+                    return nums.SumSqrs();
+                case BuiltIn_Commands_BaseClass.LIST_STAT_GEOMETRIC_MEAN:
+                    return nums.GeometricMean();
+                case BuiltIn_Commands_BaseClass.LIST_STAT_HARMONIC_MEAN:
+                    return nums.HarmonicMean();
+                default:
+                    return 0.0;
+            }
+        }
+
+        public LSL_Types.LSLInteger llGetUnixTime()
+        {
+            m_host.AddScriptLPS(1);
+            return Util.UnixTimeSinceEpoch();
+        }
+
+        public LSL_Types.LSLInteger llGetParcelFlags(LSL_Types.Vector3 pos)
+        {
+            m_host.AddScriptLPS(1);
+            return (int)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y).landData.landFlags;
+        }
+
+        public LSL_Types.LSLInteger llGetRegionFlags()
+        {
+            m_host.AddScriptLPS(1);
+            return (int)World.RegionInfo.EstateSettings.regionFlags;
+        }
+
+        public string llXorBase64StringsCorrect(string str1, string str2)
+        {
+            m_host.AddScriptLPS(1);
+            string ret = String.Empty;
+            string src1 = llBase64ToString(str1);
+            string src2 = llBase64ToString(str2);
+            int c = 0;
+            for (int i = 0; i < src1.Length; i++)
+            {
+                ret += src1[i] ^ src2[c];
+
+                c++;
+                if (c > src2.Length)
+                    c = 0;
+            }
+            return llStringToBase64(ret);
+        }
+
+        public string llHTTPRequest(string url, LSL_Types.list parameters, string body)
+        {
+            // Partial implementation: support for parameter flags needed
+            //   see http://wiki.secondlife.com/wiki/LlHTTPRequest
+            // parameter flags support are implemented in ScriptsHttpRequests.cs
+            //   in StartHttpRequest
+
+            m_host.AddScriptLPS(1);
+            IHttpRequests httpScriptMod =
+                m_ScriptEngine.World.RequestModuleInterface<IHttpRequests>();
+            List<string> param = new List<string>();
+            foreach (object o in parameters.Data)
+            {
+                param.Add(o.ToString());
+            }
+            LLUUID reqID = httpScriptMod.
+                StartHttpRequest(m_localID, m_itemID, url, param, body);
+
+            if (reqID != LLUUID.Zero)
+                return reqID.ToString();
+            else
+                return null;
+        }
+
+        public void llResetLandBanList()
+        {
+            m_host.AddScriptLPS(1);
+            LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
+            if (land.ownerID == m_host.OwnerID)
+            {
+                foreach (ParcelManager.ParcelAccessEntry entry in land.parcelAccessList)
+                {
+                    if (entry.Flags == ParcelManager.AccessList.Ban)
+                    {
+                        land.parcelAccessList.Remove(entry);
+                    }
+                }
+            }
+        }
+
+        public void llResetLandPassList()
+        {
+            m_host.AddScriptLPS(1);
+            LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).landData;
+            if (land.ownerID == m_host.OwnerID)
+            {
+                foreach (ParcelManager.ParcelAccessEntry entry in land.parcelAccessList)
+                {
+                    if (entry.Flags == ParcelManager.AccessList.Access)
+                    {
+                        land.parcelAccessList.Remove(entry);
+                    }
+                }
+            }
+        }
+
+        public LSL_Types.LSLInteger llGetParcelPrimCount(LSL_Types.Vector3 pos, int category, int sim_wide)
+        {
+            m_host.AddScriptLPS(1);
+
+            LandData land = World.GetLandData((float)pos.x, (float)pos.y);
+
+            if (land == null)
+            {
+                return 0;
+            }
+
+            else
+            {
+                if (sim_wide == 1)
+                {
+                    if (category == 0)
+                    {
+                        return land.simwidePrims;
+                    }
+
+                    else
+                    {
+                        //public int simwideArea = 0;
+                        return 0;
+                    }
+                }
+
+                else
+                {
+                    if (category == 0)//Total Prims
+                    {
+                        return 0;//land.
+                    }
+
+                    else if (category == 1)//Owner Prims
+                    {
+                        return land.ownerPrims;
+                    }
+
+                    else if (category == 2)//Group Prims
+                    {
+                        return land.groupPrims;
+                    }
+
+                    else if (category == 3)//Other Prims
+                    {
+                        return land.otherPrims;
+                    }
+
+                    else if (category == 4)//Selected
+                    {
+                        return land.selectedPrims;
+                    }
+
+                    else if (category == 5)//Temp
+                    {
+                        return 0;//land.
+                    }
+                }
+            }
+            return 0;
+        }
+
+        public LSL_Types.list llGetParcelPrimOwners(LSL_Types.Vector3 pos)
+        {
+            m_host.AddScriptLPS(1);
+            LandObject land = (LandObject)World.LandChannel.GetLandObject((float)pos.x, (float)pos.y);
+            LSL_Types.list ret = new LSL_Types.list();
+            if (land != null)
+            {
+                foreach (KeyValuePair<LLUUID, int> d in land.getLandObjectOwners())
+                {
+                    ret.Add(d.Key.ToString());
+                    ret.Add(d.Value);
+                }
+            }
+            return ret;
+        }
+
+        public LSL_Types.LSLInteger llGetObjectPrimCount(string object_id)
+        {
+            m_host.AddScriptLPS(1);
+            SceneObjectPart part = World.GetSceneObjectPart(new LLUUID(object_id));
+            if (part == null)
+            {
+                return 0;
+            }
+            else
+            {
+                return part.ParentGroup.Children.Count;
+            }
+        }
+
+        public LSL_Types.LSLInteger llGetParcelMaxPrims(LSL_Types.Vector3 pos, int sim_wide)
+        {
+            m_host.AddScriptLPS(1);
+            // Alondria: This currently just is utilizing the normal grid's 0.22 prims/m2 calculation
+            // Which probably will be irrelevent in OpenSim....
+            LandData land = World.GetLandData((float)pos.x, (float)pos.y);
+
+            float bonusfactor = World.RegionInfo.EstateSettings.objectBonusFactor;
+
+            if (land == null)
+            {
+                return 0;
+            }
+
+            if (sim_wide == 1)
+            {
+                decimal v = land.simwideArea * (decimal)(0.22) * (decimal)bonusfactor;
+
+                return (int)v;
+            }
+
+            else
+            {
+                decimal v = land.area * (decimal)(0.22) * (decimal)bonusfactor;
+
+                return (int)v;
+            }
+
+        }
+
+        public LSL_Types.list llGetParcelDetails(LSL_Types.Vector3 pos, LSL_Types.list param)
+        {
+            m_host.AddScriptLPS(1);
+            LandData land = World.GetLandData((float)pos.x, (float)pos.y);
+            if (land == null)
+            {
+                return new LSL_Types.list(0);
+            }
+            LSL_Types.list ret = new LSL_Types.list();
+            foreach (object o in param.Data)
+            {
+                switch (o.ToString())
+                {
+                    case "0":
+                        ret = ret + new LSL_Types.list(land.landName);
+                        break;
+                    case "1":
+                        ret = ret + new LSL_Types.list(land.landDesc);
+                        break;
+                    case "2":
+                        ret = ret + new LSL_Types.list(land.ownerID.ToString());
+                        break;
+                    case "3":
+                        ret = ret + new LSL_Types.list(land.groupID.ToString());
+                        break;
+                    case "4":
+                        ret = ret + new LSL_Types.list(land.area);
+                        break;
+                    default:
+                        ret = ret + new LSL_Types.list(0);
+                        break;
+                }
+            }
+            return ret;
+        }
+
+        public void llSetLinkTexture(int linknumber, string texture, int face)
+        {
+            m_host.AddScriptLPS(1);
+            NotImplemented("llSetLinkTexture");
+        }
+
+        public string llStringTrim(string src, int type)
+        {
+            m_host.AddScriptLPS(1);
+            if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM_HEAD) { return src.TrimStart(); }
+            if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM_TAIL) { return src.TrimEnd(); }
+            if (type == (int)BuiltIn_Commands_BaseClass.STRING_TRIM) { return src.Trim(); }
+            return src;
+        }
+
+        public LSL_Types.list llGetObjectDetails(string id, LSL_Types.list args)
+        {
+            m_host.AddScriptLPS(1);
+            LSL_Types.list ret = new LSL_Types.list();
+            LLUUID key = new LLUUID();
+            if (LLUUID.TryParse(id, out key))
+            {
+                ScenePresence av = World.GetScenePresence(key);
+
+                if (av != null)
+                {
+                    foreach (object o in args.Data)
+                    {
+                        switch (o.ToString())
+                        {
+                            case "1":
+                                ret.Add(av.Firstname + " " + av.Lastname);
+                                break;
+                            case "2":
+                                ret.Add("");
+                                break;
+                            case "3":
+                                ret.Add(new LSL_Types.Vector3((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
+                                break;
+                            case "4":
+                                ret.Add(new LSL_Types.Quaternion((double)av.Rotation.x, (double)av.Rotation.y, (double)av.Rotation.z, (double)av.Rotation.w));
+                                break;
+                            case "5":
+                                ret.Add(new LSL_Types.Vector3(av.Velocity.X,av.Velocity.Y,av.Velocity.Z));
+                                break;
+                            case "6":
+                                ret.Add(id);
+                                break;
+                            case "7":
+                                ret.Add(LLUUID.Zero.ToString());
+                                break;
+                            case "8":
+                                ret.Add(LLUUID.Zero.ToString());
+                                break;
+                        }
+                    }
+                    return ret;
+                }
+                SceneObjectPart obj = World.GetSceneObjectPart(key);
+                if (obj != null)
+                {
+                    foreach (object o in args.Data)
+                    {
+                        switch (o.ToString())
+                        {
+                            case "1":
+                                ret.Add(obj.Name);
+                                break;
+                            case "2":
+                                ret.Add(obj.Description);
+                                break;
+                            case "3":
+                                ret.Add(new LSL_Types.Vector3(obj.AbsolutePosition.X,obj.AbsolutePosition.Y,obj.AbsolutePosition.Z));
+                                break;
+                            case "4":
+                                ret.Add(new LSL_Types.Quaternion(obj.RotationOffset.X, obj.RotationOffset.Y, obj.RotationOffset.Z, obj.RotationOffset.W));
+                                break;
+                            case "5":
+                                ret.Add(new LSL_Types.Vector3(obj.Velocity.X, obj.Velocity.Y, obj.Velocity.Z));
+                                break;
+                            case "6":
+                                ret.Add(obj.OwnerID.ToString());
+                                break;
+                            case "7":
+                                ret.Add(obj.GroupID.ToString());
+                                break;
+                            case "8":
+                                ret.Add(obj.CreatorID.ToString());
+                                break;
+                        }
+                    }
+                    return ret;
+                }
+            }
+            return new LSL_Types.list();
+        }
+
+
+        internal LLUUID ScriptByName(string name)
+        {
+            foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
+            {
+                if (item.Type == 10 && item.Name == name)
+                    return item.ItemID;
+            }
+            return LLUUID.Zero;
+        }
+
+        internal void ShoutError(string msg)
+        {
+            llShout(BuiltIn_Commands_BaseClass.DEBUG_CHANNEL, msg);
+        }
+
+
+
+        internal void NotImplemented(string command)
+        {
+            if (throwErrorOnNotImplemented)
+                throw new NotImplementedException("Command not implemented: " + command);
+        }
+
+        internal void Deprecated(string command)
+        {
+            throw new Exception("Command deprecated: " + command);
+        }
+
+        internal void LSLError(string msg)
+        {
+            throw new Exception("LSL Runtime Error: " + msg);
+        }
+
+        public delegate void AssetRequestCallback(LLUUID assetID, AssetBase asset);
+        private void WithNotecard(LLUUID assetID, AssetRequestCallback cb)
+        {
+            World.AssetCache.GetAsset(assetID, delegate(LLUUID i, AssetBase a) { cb(i, a); }, false);
+        }
+
+        public string llGetNumberOfNotecardLines(string name)
+        {
+            m_host.AddScriptLPS(1);
+
+            foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
+            {
+                if (item.Type == 7 && item.Name == name)
+                {
+                    LLUUID tid = m_ScriptEngine.m_ASYNCLSLCommandManager.
+                            m_Dataserver.RegisterRequest(m_localID,
+                            m_itemID, item.AssetID.ToString());
+                    if(NotecardCache.IsCached(item.AssetID))
+                    {
+                        m_ScriptEngine.m_ASYNCLSLCommandManager.
+                        m_Dataserver.DataserverReply(item.AssetID.ToString(),
+                                NotecardCache.GetLines(item.AssetID).ToString());
+                        return tid.ToString();
+                    }
+                    WithNotecard(item.AssetID, delegate (LLUUID id, AssetBase a)
+                    {
+                        System.Text.ASCIIEncoding enc =
+                            new System.Text.ASCIIEncoding();
+                        string data = enc.GetString(a.Data);
+                        Console.WriteLine(data);
+                        NotecardCache.Cache(id, data);
+                        m_ScriptEngine.m_ASYNCLSLCommandManager.
+                                m_Dataserver.DataserverReply(id.ToString(),
+                                NotecardCache.GetLines(id).ToString());
+                    });
+
+                    return tid.ToString();
+                }
+            }
+            return LLUUID.Zero.ToString();
+        }
+
+        public string llGetNotecardLine(string name, int line)
+        {
+            m_host.AddScriptLPS(1);
+
+            foreach (TaskInventoryItem item in m_host.TaskInventory.Values)
+            {
+                if (item.Type == 7 && item.Name == name)
+                {
+                    LLUUID tid = m_ScriptEngine.m_ASYNCLSLCommandManager.
+                            m_Dataserver.RegisterRequest(m_localID,
+                            m_itemID, item.AssetID.ToString());
+                    if(NotecardCache.IsCached(item.AssetID))
+                    {
+                        m_ScriptEngine.m_ASYNCLSLCommandManager.
+                        m_Dataserver.DataserverReply(item.AssetID.ToString(),
+                                NotecardCache.GetLine(item.AssetID, line));
+                        return tid.ToString();
+                    }
+                    WithNotecard(item.AssetID, delegate (LLUUID id, AssetBase a)
+                    {
+                        System.Text.ASCIIEncoding enc =
+                            new System.Text.ASCIIEncoding();
+                        string data = enc.GetString(a.Data);
+                        Console.WriteLine(data);
+                        NotecardCache.Cache(id, data);
+                        m_ScriptEngine.m_ASYNCLSLCommandManager.
+                                m_Dataserver.DataserverReply(id.ToString(),
+                                NotecardCache.GetLine(id, line));
+                    });
+
+                    return tid.ToString();
+                }
+            }
+
+            return String.Empty;
+        }
+
+    }
+
+    public class NotecardCache
+    {
+        private class Notecard
+        {
+            public string[] text;
+            public DateTime lastRef;
+        }
+
+        private static Dictionary<LLUUID, Notecard> m_Notecards =
+                new Dictionary<LLUUID, Notecard>();
+        
+        public static void Cache(LLUUID assetID, string text)
+        {
+            CacheCheck();
+
+            lock(m_Notecards)
+            {
+                if(m_Notecards.ContainsKey(assetID))
+                    return;
+
+                Notecard nc = new Notecard();
+                nc.lastRef=DateTime.Now;
+                nc.text = ParseText(text.Replace("\r", "").Split('\n'));
+                m_Notecards[assetID] = nc;
+            }
+        }
+
+        private static string[] ParseText(string[] input)
+        {
+            int idx=0;
+            int level=0;
+            List<string> output = new List<string>();
+            string[] words;
+
+            while(idx < input.Length)
+            {
+                if(input[idx] == "{")
+                {
+                    level++;
+                    idx++;
+                    continue;
+                }
+                if(input[idx]== "}")
+                {
+                    level--;
+                    idx++;
+                    continue;
+                }
+
+                switch(level)
+                {
+                case 0:
+                    words = input[idx].Split(' '); // Linden text ver
+                    int version = int.Parse(words[3]);
+                    if(version != 2)
+                        return new String[0];
+                    break;
+                case 1:
+                    words = input[idx].Split(' ');
+                    if(words[0] == "LLEmbeddedItems")
+                        break;
+                    if(words[0] == "Text")
+                    {
+                        int len = int.Parse(words[2]);
+                        idx++;
+
+                        int count=-1;
+
+                        while(count < len)
+                        {
+                            int l = input[idx].Length;
+                            string ln = input[idx];
+
+                            int need = len-count-1;
+                            if(ln.Length > need)
+                                ln=ln.Substring(0, need);
+
+                            output.Add(ln);
+                            count+=ln.Length+1;
+                            idx++;
+                        }
+                            
+                        return output.ToArray();
+                    }
+                    break;
+                case 2:
+                    words = input[idx].Split(' '); // count
+                    if(words[0] == "count")
+                    {
+                        int c = int.Parse(words[1]);
+                        if(c > 0)
+                            return new String[0];
+                        break;
+                    }
+                    break;
+                }
+                idx++;
+            }
+            return output.ToArray();
+        }
+
+        public static bool IsCached(LLUUID assetID)
+        {
+            lock(m_Notecards)
+            {
+                return m_Notecards.ContainsKey(assetID);
+            }
+        }
+
+        public static int GetLines(LLUUID assetID)
+        {
+            if(!IsCached(assetID))
+                return -1;
+
+            lock(m_Notecards)
+            {
+                m_Notecards[assetID].lastRef = DateTime.Now;
+                return m_Notecards[assetID].text.Length;
+            }
+        }
+
+        public static string GetLine(LLUUID assetID, int line)
+        {
+            if(line < 0)
+                return "";
+
+            string data;
+
+            if(!IsCached(assetID))
+                return "";
+
+            lock(m_Notecards)
+            {
+                m_Notecards[assetID].lastRef = DateTime.Now;
+
+                if(line >= m_Notecards[assetID].text.Length)
+                    return "\n\n\n";
+
+                data=m_Notecards[assetID].text[line];
+                if(data.Length > 255)
+                    data = data.Substring(0, 255);
+
+                return data;
+            }
+        }
+
+        public static void CacheCheck()
+        {
+            foreach (LLUUID key in new List<LLUUID>(m_Notecards.Keys))
+            {
+                Notecard nc = m_Notecards[key];
+                if(nc.lastRef.AddSeconds(30) < DateTime.Now)
+                    m_Notecards.Remove(key);
+            }
+        }
+
+    }
+}

+ 553 - 0
OpenSim/Region/ScriptEngine/XEngine/OSSL_ScriptCommands.cs

@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+using System;
+using Axiom.Math;
+using libsecondlife;
+using Nini.Config;
+using OpenSim.Framework.Console;
+using OpenSim.Region.Environment.Interfaces;
+using OpenSim.Region.Environment.Scenes;
+using OpenSim.Region.ScriptEngine.XEngine.Script;
+
+namespace OpenSim.Region.ScriptEngine.XEngine
+{
+    [Serializable]
+    public class OSSL_ScriptCommands : MarshalByRefObject, IOSSL_ScriptCommands
+    {
+        internal XEngine m_ScriptEngine;
+        internal XScriptInstance m_Instance;
+        internal SceneObjectPart m_host;
+        internal uint m_localID;
+        internal LLUUID m_itemID;
+
+        public OSSL_ScriptCommands(XEngine scriptEngine,
+                XScriptInstance instance, SceneObjectPart host,
+                uint localID, LLUUID itemID)
+        {
+            m_ScriptEngine = scriptEngine;
+            m_Instance = instance;
+            m_host = host;
+            m_localID = localID;
+            m_itemID = itemID;
+        }
+
+
+        //
+        // OpenSim functions
+        //
+
+        public int osTerrainSetHeight(int x, int y, double val)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osTerrainSetHeight: permission denied");
+                return 0;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (x > 255 || x < 0 || y > 255 || y < 0)
+                OSSLError("osTerrainSetHeight: Coordinate out of bounds");
+
+            if (World.ExternalChecks.ExternalChecksCanTerraformLand(m_host.OwnerID, new LLVector3(x, y, 0)))
+            {
+                World.Heightmap[x, y] = val;
+                return 1;
+            }
+            else
+            {
+                return 0;
+            }
+        }
+
+        public double osTerrainGetHeight(int x, int y)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osTerrainGetHeight: permission denied");
+                return 0.0;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (x > 255 || x < 0 || y > 255 || y < 0)
+                OSSLError("osTerrainGetHeight: Coordinate out of bounds");
+
+            return World.Heightmap[x, y];
+        }
+
+        public int osRegionRestart(double seconds)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osRegionRestart: permission denied");
+                return 0;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (World.ExternalChecks.ExternalChecksCanIssueEstateCommand(m_host.OwnerID))
+            {
+                World.Restart((float)seconds);
+                return 1;
+            }
+            else
+            {
+                return 0;
+            }
+        }
+
+        public void osRegionNotice(string msg)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osRegionNotice: permission denied");
+                return;
+            }
+
+            m_host.AddScriptLPS(1);
+            World.SendGeneralAlert(msg);
+        }
+
+        public void osSetRot(LLUUID target, Quaternion rotation)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetRot: permission denied");
+                return;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (World.Entities.ContainsKey(target))
+            {
+                World.Entities[target].Rotation = rotation;
+            }
+            else
+            {
+                OSSLError("osSetRot: Invalid target");
+            }
+        }
+
+        public string osSetDynamicTextureURL(string dynamicID, string contentType, string url, string extraParams,
+                                             int timer)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetDynamicTextureURL: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (dynamicID == String.Empty)
+            {
+                IDynamicTextureManager textureManager = World.RequestModuleInterface<IDynamicTextureManager>();
+                LLUUID createdTexture =
+                    textureManager.AddDynamicTextureURL(World.RegionInfo.RegionID, m_host.UUID, contentType, url,
+                                                        extraParams, timer);
+                return createdTexture.ToString();
+            }
+            else
+            {
+                //TODO update existing dynamic textures
+            }
+
+            return LLUUID.Zero.ToString();
+        }
+
+        public string osSetDynamicTextureURLBlend(string dynamicID, string contentType, string url, string extraParams,
+                                             int timer, int alpha)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetDynamicTextureURLBlend: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (dynamicID == String.Empty)
+            {
+                IDynamicTextureManager textureManager = World.RequestModuleInterface<IDynamicTextureManager>();
+                LLUUID createdTexture =
+                    textureManager.AddDynamicTextureURL(World.RegionInfo.RegionID, m_host.UUID, contentType, url,
+                                                        extraParams, timer, true, (byte) alpha);
+                return createdTexture.ToString();
+            }
+            else
+            {
+                //TODO update existing dynamic textures
+            }
+
+            return LLUUID.Zero.ToString();
+        }
+
+        public string osSetDynamicTextureData(string dynamicID, string contentType, string data, string extraParams,
+                                           int timer)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetDynamicTextureData: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (dynamicID == String.Empty)
+            {
+                IDynamicTextureManager textureManager = World.RequestModuleInterface<IDynamicTextureManager>();
+                if (textureManager != null)
+                {
+                    LLUUID createdTexture =
+                        textureManager.AddDynamicTextureData(World.RegionInfo.RegionID, m_host.UUID, contentType, data,
+                                                            extraParams, timer);
+                    return createdTexture.ToString();
+                }
+            }
+            else
+            {
+                //TODO update existing dynamic textures
+            }
+
+            return LLUUID.Zero.ToString();
+        }
+
+        public string osSetDynamicTextureDataBlend(string dynamicID, string contentType, string data, string extraParams,
+                                          int timer, int alpha)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetDynamicTextureDataBlend: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (dynamicID == String.Empty)
+            {
+                IDynamicTextureManager textureManager = World.RequestModuleInterface<IDynamicTextureManager>();
+                if (textureManager != null)
+                {
+                    LLUUID createdTexture =
+                        textureManager.AddDynamicTextureData(World.RegionInfo.RegionID, m_host.UUID, contentType, data,
+                                                            extraParams, timer, true, (byte) alpha);
+                    return createdTexture.ToString();
+                }
+            }
+            else
+            {
+                //TODO update existing dynamic textures
+            }
+
+            return LLUUID.Zero.ToString();
+        }
+
+        public bool osConsoleCommand(string command)
+        {
+            m_host.AddScriptLPS(1);
+            if (m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowosConsoleCommand", false))
+            {
+                if (World.ExternalChecks.ExternalChecksCanRunConsoleCommand(m_host.OwnerID))
+                {
+                    MainConsole.Instance.RunCommand(command);
+                    return true;
+                }
+                return false;
+            }
+            return false;
+        }
+        public void osSetPrimFloatOnWater(int floatYN)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetPrimFloatOnWater: permission denied");
+                return;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (m_host.ParentGroup != null)
+            {
+                if (m_host.ParentGroup.RootPart != null)
+                {
+                    m_host.ParentGroup.RootPart.SetFloatOnWater(floatYN);
+                }
+            }
+        }
+
+        // Adam's super super custom animation functions
+        public void osAvatarPlayAnimation(string avatar, string animation)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osAvatarPlayAnimation: permission denied");
+                return;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (World.Entities.ContainsKey(avatar) && World.Entities[avatar] is ScenePresence)
+            {
+                ScenePresence target = (ScenePresence)World.Entities[avatar];
+                target.AddAnimation(avatar);
+            }
+        }
+
+        public void osAvatarStopAnimation(string avatar, string animation)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osAvatarStopAnimation: permission denied");
+                return;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (World.Entities.ContainsKey(avatar) && World.Entities[avatar] is ScenePresence)
+            {
+                ScenePresence target = (ScenePresence)World.Entities[avatar];
+                target.RemoveAnimation(animation);
+            }
+        }
+
+        //Texture draw functions
+        public string osMovePen(string drawList, int x, int y)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osMovePen: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            drawList += "MoveTo " + x + "," + y + ";";
+            return drawList;
+        }
+
+        public string osDrawLine(string drawList, int startX, int startY, int endX, int endY)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osDrawLine: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            drawList += "MoveTo "+ startX+","+ startY +"; LineTo "+endX +","+endY +"; ";
+            return drawList;
+        }
+
+        public string osDrawLine(string drawList, int endX, int endY)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osDrawLine: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            drawList += "LineTo " + endX + "," + endY + "; ";
+            return drawList;
+        }
+
+        public string osDrawText(string drawList, string text)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osDrawText: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            drawList += "Text " + text + "; ";
+            return drawList;
+        }
+
+        public string osDrawEllipse(string drawList, int width, int height)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osDrawEllipse: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            drawList += "Ellipse " + width + "," + height + "; ";
+            return drawList;
+        }
+
+        public string osDrawRectangle(string drawList, int width, int height)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osDrawRectangle: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            drawList += "Rectangle " + width + "," + height + "; ";
+            return drawList;
+        }
+
+        public string osDrawFilledRectangle(string drawList, int width, int height)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osDrawFilledRectangle: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            drawList += "FillRectangle " + width + "," + height + "; ";
+            return drawList;
+        }
+
+        public string osSetFontSize(string drawList, int fontSize)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetFontSize: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            drawList += "FontSize "+ fontSize +"; ";
+            return drawList;
+        }
+
+        public string osSetPenSize(string drawList, int penSize)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetPenSize: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            drawList += "PenSize " + penSize + "; ";
+            return drawList;
+        }
+
+        public string osSetPenColour(string drawList, string colour)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetPenColour: permission denied");
+                return String.Empty;
+            }
+
+            m_host.AddScriptLPS(1);
+            drawList += "PenColour " + colour + "; ";
+            return drawList;
+        }
+
+        public string osDrawImage(string drawList, int width, int height, string imageUrl)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osDrawImage: permission denied");
+                return String.Empty;
+            }
+
+           m_host.AddScriptLPS(1);
+           drawList +="Image " +width + "," + height+ ","+ imageUrl +"; " ;
+           return drawList;
+        }
+
+        public void osSetStateEvents(int events)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetStateEvents: permission denied");
+                return;
+            }
+
+            m_host.SetScriptEvents(m_itemID, events);
+        }
+
+        public void osSetRegionWaterHeight(double height)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetRegionWaterHeight: permission denied");
+                return;
+            }
+
+            m_host.AddScriptLPS(1);
+            //Check to make sure that the script's owner is the estate manager/master
+            //World.Permissions.GenericEstatePermission(
+            if (World.ExternalChecks.ExternalChecksCanBeGodLike(m_host.OwnerID))
+            {
+                World.EventManager.TriggerRequestChangeWaterHeight((float)height);
+            }
+        }
+
+        public double osList2Double(LSL_Types.list src, int index)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osList2Double: permission denied");
+                return 0.0;
+            }
+
+            m_host.AddScriptLPS(1);
+            if (index < 0)
+            {
+                index = src.Length + index;
+            }
+            if (index >= src.Length)
+            {
+                return 0.0;
+            }
+            return Convert.ToDouble(src.Data[index]);
+        }
+
+        public void osSetParcelMediaURL(string url)
+        {
+            if (!m_ScriptEngine.ScriptConfigSource.GetBoolean("AllowOSFunctions", false))
+            {
+                OSSLError("osSetParcelMediaURL: permission denied");
+                return;
+            }
+
+            m_host.AddScriptLPS(1);
+            LLUUID landowner = World.GetLandOwner(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
+
+            if (landowner == LLUUID.Zero)
+            {
+                return;
+            }
+
+            if (landowner != m_host.ObjectOwner)
+            {
+                return;
+            }
+
+            World.SetLandMediaURL(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y, url);
+        }
+
+        public Scene World
+        {
+            get { return m_ScriptEngine.World; }
+        }
+
+        internal void OSSLError(string msg)
+        {
+            throw new Exception("OSSL Runtime Error: " + msg);
+        }
+    }
+}

+ 65 - 0
OpenSim/Region/ScriptEngine/XEngine/Script/AssemblyResolver.cs

@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.IO;
+using System.Reflection;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.Script
+{
+    [Serializable]
+    public class AssemblyResolver
+    {
+        public static Assembly OnAssemblyResolve(object sender,
+                ResolveEventArgs args)
+        {
+            if(!(sender is System.AppDomain))
+                return null;
+
+            AppDomain myDomain = (AppDomain)sender;
+            string dirName = myDomain.FriendlyName;
+
+            string[] pathList=new string[] {"bin", "ScriptEngines",
+                    Path.Combine("ScriptEngines", dirName)};
+
+            string assemblyName = args.Name;
+            if(assemblyName.IndexOf(",") != -1)
+                assemblyName=args.Name.Substring(0, args.Name.IndexOf(","));
+
+            foreach (string s in pathList)
+            {
+                string path=Path.Combine(Directory.GetCurrentDirectory(),
+                        Path.Combine(s, assemblyName))+".dll";
+                        
+                if(File.Exists(path))
+                    return Assembly.LoadFrom(path);
+            }
+            
+            return null;
+        }
+    }
+}

+ 2393 - 0
OpenSim/Region/ScriptEngine/XEngine/Script/BuiltIn_Commands_BaseClass.cs

@@ -0,0 +1,2393 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Runtime.Remoting.Lifetime;
+using System.Threading;
+using System.Reflection;
+using System.Collections;
+using System.Collections.Generic;
+using OpenSim.Region.Environment.Interfaces;
+using integer = OpenSim.Region.ScriptEngine.XEngine.Script.LSL_Types.LSLInteger;
+using key = System.String;
+using vector = OpenSim.Region.ScriptEngine.XEngine.Script.LSL_Types.Vector3;
+using rotation = OpenSim.Region.ScriptEngine.XEngine.Script.LSL_Types.Quaternion;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.Script
+{
+    public class BuiltIn_Commands_BaseClass : MarshalByRefObject, IOSSL_ScriptCommands, ILSL_ScriptCommands, IScript
+    {
+        //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+        // Object never expires
+        public override Object InitializeLifetimeService()
+        {
+            //Console.WriteLine("LSL_BaseClass: InitializeLifetimeService()");
+            //            return null;
+            ILease lease = (ILease)base.InitializeLifetimeService();
+
+            if (lease.CurrentState == LeaseState.Initial)
+            {
+                lease.InitialLeaseTime = TimeSpan.Zero; // TimeSpan.FromMinutes(1);
+                //lease.SponsorshipTimeout = TimeSpan.FromMinutes(2);
+                //lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
+            }
+            return lease;
+        }
+
+        public ILSL_ScriptCommands m_LSL_Functions;
+        public IOSSL_ScriptCommands m_OSSL_Functions;
+
+        public BuiltIn_Commands_BaseClass()
+        {
+        }
+
+        public Type Start(ILSL_ScriptCommands LSL_Functions, IOSSL_ScriptCommands OSSL_Functions)
+        {
+            m_LSL_Functions = LSL_Functions;
+            m_OSSL_Functions = OSSL_Functions;
+            m_InitialValues=GetVars();
+            return GetType();
+        }
+
+        private Dictionary<string, object> m_InitialValues =
+                new Dictionary<string, object>();
+        private Dictionary<string, FieldInfo> m_Fields =
+                new Dictionary<string, FieldInfo>();
+
+        public Dictionary<string, object> GetVars()
+        {
+            m_Fields.Clear();
+
+            Dictionary<string, object> vars = new Dictionary<string, object>();
+
+            Type t = GetType();
+
+            FieldInfo[] fields = t.GetFields(BindingFlags.NonPublic |
+                                             BindingFlags.Public |
+                                             BindingFlags.Instance |
+                                             BindingFlags.DeclaredOnly);
+
+            foreach (FieldInfo field in fields)
+            {
+                m_Fields[field.Name]=field;
+
+                vars[field.Name]=field.GetValue(this);
+            }
+
+            return vars;
+        }
+
+        public void SetVars(Dictionary<string, object> vars)
+        {
+            foreach (KeyValuePair<string, object> var in vars)
+            {
+                if(m_Fields.ContainsKey(var.Key))
+                {
+                    m_Fields[var.Key].SetValue(this, var.Value);
+                }
+            }
+        }
+
+        public void ResetVars()
+        {
+            SetVars(m_InitialValues);
+        }
+
+        public string State
+        {
+            get { return m_LSL_Functions.State; }
+            set { m_LSL_Functions.State = value; }
+        }
+
+        public void state(string newState)
+        {
+            m_LSL_Functions.state(newState);
+        }
+
+        public void llSay(int channelID, string text)
+        {
+            m_LSL_Functions.llSay(channelID, text);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        // They are only forwarders to LSL_BuiltIn_Commands.cs
+        //
+
+        public ICommander GetCommander(string name)
+        {
+            return m_LSL_Functions.GetCommander(name);
+        }
+
+        public double llSin(double f)
+        {
+            return m_LSL_Functions.llSin(f);
+        }
+        public double llCos(double f)
+        {
+            return m_LSL_Functions.llCos(f);
+        }
+
+        public double llTan(double f)
+        {
+            return m_LSL_Functions.llTan(f);
+        }
+
+        public double llAtan2(double x, double y)
+        {
+            return m_LSL_Functions.llAtan2(x, y);
+        }
+
+        public double llSqrt(double f)
+        {
+            return m_LSL_Functions.llSqrt(f);
+        }
+
+        public double llPow(double fbase, double fexponent)
+        {
+            return m_LSL_Functions.llPow(fbase, fexponent);
+        }
+
+        public LSL_Types.LSLInteger llAbs(int i)
+        {
+            return m_LSL_Functions.llAbs(i);
+        }
+
+        public double llFabs(double f)
+        {
+            return m_LSL_Functions.llFabs(f);
+        }
+
+        public double llFrand(double mag)
+        {
+            return m_LSL_Functions.llFrand(mag);
+        }
+
+        public LSL_Types.LSLInteger llFloor(double f)
+        {
+            return m_LSL_Functions.llFloor(f);
+        }
+
+        public LSL_Types.LSLInteger llCeil(double f)
+        {
+            return m_LSL_Functions.llCeil(f);
+        }
+
+        public LSL_Types.LSLInteger llRound(double f)
+        {
+            return m_LSL_Functions.llRound(f);
+        }
+
+        public double llVecMag(vector v)
+        {
+            return m_LSL_Functions.llVecMag(v);
+        }
+
+        public vector llVecNorm(vector v)
+        {
+            return m_LSL_Functions.llVecNorm(v);
+        }
+
+        public double llVecDist(vector a, vector b)
+        {
+            return m_LSL_Functions.llVecDist(a, b);
+        }
+
+        public vector llRot2Euler(rotation r)
+        {
+            return m_LSL_Functions.llRot2Euler(r);
+        }
+
+        public rotation llEuler2Rot(vector v)
+        {
+            return m_LSL_Functions.llEuler2Rot(v);
+        }
+
+        public rotation llAxes2Rot(vector fwd, vector left, vector up)
+        {
+            return m_LSL_Functions.llAxes2Rot(fwd, left, up);
+        }
+
+        public vector llRot2Fwd(rotation r)
+        {
+            return m_LSL_Functions.llRot2Fwd(r);
+        }
+
+        public vector llRot2Left(rotation r)
+        {
+            return m_LSL_Functions.llRot2Left(r);
+        }
+
+        public vector llRot2Up(rotation r)
+        {
+            return m_LSL_Functions.llRot2Up(r);
+        }
+
+        public rotation llRotBetween(vector start, vector end)
+        {
+            return m_LSL_Functions.llRotBetween(start, end);
+        }
+
+        public void llWhisper(int channelID, string text)
+        {
+            m_LSL_Functions.llWhisper(channelID, text);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public void llShout(int channelID, string text)
+        {
+            m_LSL_Functions.llShout(channelID, text);
+        }
+
+        public void llRegionSay(int channelID, string text)
+        {
+            m_LSL_Functions.llRegionSay(channelID, text);
+        }
+
+        public LSL_Types.LSLInteger llListen(int channelID, string name, string ID, string msg)
+        {
+            return m_LSL_Functions.llListen(channelID, name, ID, msg);
+        }
+
+        public void llListenControl(int number, int active)
+        {
+            m_LSL_Functions.llListenControl(number, active);
+        }
+
+        public void llListenRemove(int number)
+        {
+            m_LSL_Functions.llListenRemove(number);
+        }
+
+        public void llSensor(string name, string id, int type, double range, double arc)
+        {
+            m_LSL_Functions.llSensor(name, id, type, range, arc);
+        }
+
+        public void llSensorRepeat(string name, string id, int type, double range, double arc, double rate)
+        {
+            m_LSL_Functions.llSensorRepeat(name, id, type, range, arc, rate);
+        }
+
+        public void llSensorRemove()
+        {
+            m_LSL_Functions.llSensorRemove();
+        }
+
+        public string llDetectedName(int number)
+        {
+            return m_LSL_Functions.llDetectedName(number);
+        }
+
+        public string llDetectedKey(int number)
+        {
+            return m_LSL_Functions.llDetectedKey(number);
+        }
+
+        public string llDetectedOwner(int number)
+        {
+            return m_LSL_Functions.llDetectedOwner(number);
+        }
+
+        public LSL_Types.LSLInteger llDetectedType(int number)
+        {
+            return m_LSL_Functions.llDetectedType(number);
+        }
+
+        public vector llDetectedPos(int number)
+        {
+            return m_LSL_Functions.llDetectedPos(number);
+        }
+
+        public vector llDetectedVel(int number)
+        {
+            return m_LSL_Functions.llDetectedVel(number);
+        }
+
+        public vector llDetectedGrab(int number)
+        {
+            return m_LSL_Functions.llDetectedGrab(number);
+        }
+
+        public rotation llDetectedRot(int number)
+        {
+            return m_LSL_Functions.llDetectedRot(number);
+        }
+
+        public LSL_Types.LSLInteger llDetectedGroup(int number)
+        {
+            return m_LSL_Functions.llDetectedGroup(number);
+        }
+
+        public LSL_Types.LSLInteger llDetectedLinkNumber(int number)
+        {
+            return m_LSL_Functions.llDetectedLinkNumber(number);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public void llDie()
+        {
+            m_LSL_Functions.llDie();
+        }
+
+        public double llGround(vector offset)
+        {
+            return m_LSL_Functions.llGround(offset);
+        }
+
+        public double llCloud(vector offset)
+        {
+            return m_LSL_Functions.llCloud(offset);
+        }
+
+        public vector llWind(vector offset)
+        {
+            return m_LSL_Functions.llWind(offset);
+        }
+
+        public void llSetStatus(int status, int value)
+        {
+            m_LSL_Functions.llSetStatus(status, value);
+        }
+
+        public LSL_Types.LSLInteger llGetStatus(int status)
+        {
+            return m_LSL_Functions.llGetStatus(status);
+        }
+
+        public void llSetScale(vector scale)
+        {
+            m_LSL_Functions.llSetScale(scale);
+        }
+
+        public vector llGetScale()
+        {
+            return m_LSL_Functions.llGetScale();
+        }
+
+        public void llSetColor(vector color, int face)
+        {
+            m_LSL_Functions.llSetColor(color, face);
+        }
+
+        public double llGetAlpha(int face)
+        {
+            return m_LSL_Functions.llGetAlpha(face);
+        }
+
+        public void llSetAlpha(double alpha, int face)
+        {
+            m_LSL_Functions.llSetAlpha(alpha, face);
+        }
+
+        public vector llGetColor(int face)
+        {
+            return m_LSL_Functions.llGetColor(face);
+        }
+
+        public void llSetTexture(string texture, int face)
+        {
+            m_LSL_Functions.llSetTexture(texture, face);
+        }
+
+        public void llScaleTexture(double u, double v, int face)
+        {
+            m_LSL_Functions.llScaleTexture(u, v, face);
+        }
+
+        public void llOffsetTexture(double u, double v, int face)
+        {
+            m_LSL_Functions.llOffsetTexture(u, v, face);
+        }
+
+        public void llRotateTexture(double rotation, int face)
+        {
+            m_LSL_Functions.llRotateTexture(rotation, face);
+        }
+
+        public string llGetTexture(int face)
+        {
+            return m_LSL_Functions.llGetTexture(face);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public void llSetPos(vector pos)
+        {
+            m_LSL_Functions.llSetPos(pos);
+        }
+
+        public vector llGetPos()
+        {
+            return m_LSL_Functions.llGetPos();
+        }
+
+        public vector llGetLocalPos()
+        {
+            return m_LSL_Functions.llGetLocalPos();
+        }
+
+        public void llSetRot(rotation rot)
+        {
+            m_LSL_Functions.llSetRot(rot);
+        }
+
+        public rotation llGetRot()
+        {
+            return m_LSL_Functions.llGetRot();
+        }
+
+        public rotation llGetLocalRot()
+        {
+            return m_LSL_Functions.llGetLocalRot();
+        }
+
+        public void llSetForce(vector force, int local)
+        {
+            m_LSL_Functions.llSetForce(force, local);
+        }
+
+        public vector llGetForce()
+        {
+            return m_LSL_Functions.llGetForce();
+        }
+
+        public LSL_Types.LSLInteger llTarget(vector position, double range)
+        {
+            return m_LSL_Functions.llTarget(position, range);
+        }
+
+        public void llTargetRemove(int number)
+        {
+            m_LSL_Functions.llTargetRemove(number);
+        }
+
+        public LSL_Types.LSLInteger llRotTarget(rotation rot, double error)
+        {
+            return m_LSL_Functions.llRotTarget(rot, error);
+        }
+
+        public void llRotTargetRemove(int number)
+        {
+            m_LSL_Functions.llRotTargetRemove(number);
+        }
+
+        public void llMoveToTarget(vector target, double tau)
+        {
+            m_LSL_Functions.llMoveToTarget(target, tau);
+        }
+
+        public void llStopMoveToTarget()
+        {
+            m_LSL_Functions.llStopMoveToTarget();
+        }
+
+        public void llApplyImpulse(vector force, int local)
+        {
+            m_LSL_Functions.llApplyImpulse(force, local);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public void llApplyRotationalImpulse(vector force, int local)
+        {
+            m_LSL_Functions.llApplyRotationalImpulse(force, local);
+        }
+
+        public void llSetTorque(vector torque, int local)
+        {
+            m_LSL_Functions.llSetTorque(torque, local);
+        }
+
+        public vector llGetTorque()
+        {
+            return m_LSL_Functions.llGetTorque();
+        }
+
+        public void llSetForceAndTorque(vector force, vector torque, int local)
+        {
+            m_LSL_Functions.llSetForceAndTorque(force, torque, local);
+        }
+
+        public vector llGetVel()
+        {
+            return m_LSL_Functions.llGetVel();
+        }
+
+        public vector llGetAccel()
+        {
+            return m_LSL_Functions.llGetAccel();
+        }
+
+        public vector llGetOmega()
+        {
+            return m_LSL_Functions.llGetOmega();
+        }
+
+        public double llGetTimeOfDay()
+        {
+            return m_LSL_Functions.llGetTimeOfDay();
+        }
+
+        public double llGetWallclock()
+        {
+            return m_LSL_Functions.llGetWallclock();
+        }
+
+        public double llGetTime()
+        {
+            return m_LSL_Functions.llGetTime();
+        }
+
+        public void llResetTime()
+        {
+            m_LSL_Functions.llResetTime();
+        }
+
+        public double llGetAndResetTime()
+        {
+            return m_LSL_Functions.llGetAndResetTime();
+        }
+
+        public void llSound()
+        {
+            m_LSL_Functions.llSound();
+        }
+
+        public void llPlaySound(string sound, double volume)
+        {
+            m_LSL_Functions.llPlaySound(sound, volume);
+        }
+
+        public void llLoopSound(string sound, double volume)
+        {
+            m_LSL_Functions.llLoopSound(sound, volume);
+        }
+
+        public void llLoopSoundMaster(string sound, double volume)
+        {
+            m_LSL_Functions.llLoopSoundMaster(sound, volume);
+        }
+
+        public void llLoopSoundSlave(string sound, double volume)
+        {
+            m_LSL_Functions.llLoopSoundSlave(sound, volume);
+        }
+
+        public void llPlaySoundSlave(string sound, double volume)
+        {
+            m_LSL_Functions.llPlaySoundSlave(sound, volume);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public void llTriggerSound(string sound, double volume)
+        {
+            m_LSL_Functions.llTriggerSound(sound, volume);
+        }
+
+        public void llStopSound()
+        {
+            m_LSL_Functions.llStopSound();
+        }
+
+        public void llPreloadSound(string sound)
+        {
+            m_LSL_Functions.llPreloadSound(sound);
+        }
+
+        public string llGetSubString(string src, int start, int end)
+        {
+            return m_LSL_Functions.llGetSubString(src, start, end);
+        }
+
+        public string llDeleteSubString(string src, int start, int end)
+        {
+            return m_LSL_Functions.llDeleteSubString(src, start, end);
+        }
+
+        public string llInsertString(string dst, int position, string src)
+        {
+            return m_LSL_Functions.llInsertString(dst, position, src);
+        }
+
+        public string llToUpper(string source)
+        {
+            return m_LSL_Functions.llToUpper(source);
+        }
+
+        public string llToLower(string source)
+        {
+            return m_LSL_Functions.llToLower(source);
+        }
+
+        public LSL_Types.LSLInteger llGiveMoney(string destination, int amount)
+        {
+            return m_LSL_Functions.llGiveMoney(destination, amount);
+        }
+
+        public void llMakeExplosion()
+        {
+            m_LSL_Functions.llMakeExplosion();
+        }
+
+        public void llMakeFountain()
+        {
+            m_LSL_Functions.llMakeFountain();
+        }
+
+        public void llMakeSmoke()
+        {
+            m_LSL_Functions.llMakeSmoke();
+        }
+
+        public void llMakeFire()
+        {
+            m_LSL_Functions.llMakeFire();
+        }
+
+        public void llRezObject(string inventory, vector pos, vector vel, rotation rot, int param)
+        {
+            m_LSL_Functions.llRezObject(inventory, pos, vel, rot, param);
+        }
+
+        public void llLookAt(vector target, double strength, double damping)
+        {
+            m_LSL_Functions.llLookAt(target, strength, damping);
+        }
+
+        public void llStopLookAt()
+        {
+            m_LSL_Functions.llStopLookAt();
+        }
+
+        public void llSetTimerEvent(double sec)
+        {
+            m_LSL_Functions.llSetTimerEvent(sec);
+        }
+
+        public void llSleep(double sec)
+        {
+            m_LSL_Functions.llSleep(sec);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public double llGetMass()
+        {
+            return m_LSL_Functions.llGetMass();
+        }
+
+        public void llCollisionFilter(string name, string id, int accept)
+        {
+            m_LSL_Functions.llCollisionFilter(name, id, accept);
+        }
+
+        public void llTakeControls(int controls, int accept, int pass_on)
+        {
+            m_LSL_Functions.llTakeControls(controls, accept, pass_on);
+        }
+
+        public void llReleaseControls()
+        {
+            m_LSL_Functions.llReleaseControls();
+        }
+
+        public void llAttachToAvatar(int attachment)
+        {
+            m_LSL_Functions.llAttachToAvatar(attachment);
+        }
+
+        public void llDetachFromAvatar()
+        {
+            m_LSL_Functions.llDetachFromAvatar();
+        }
+
+        public void llTakeCamera()
+        {
+            m_LSL_Functions.llTakeCamera();
+        }
+
+        public void llReleaseCamera()
+        {
+            m_LSL_Functions.llReleaseCamera();
+        }
+
+        public string llGetOwner()
+        {
+            return m_LSL_Functions.llGetOwner();
+        }
+
+        public void llInstantMessage(string user, string message)
+        {
+            m_LSL_Functions.llInstantMessage(user, message);
+        }
+
+        public void llEmail(string address, string subject, string message)
+        {
+            m_LSL_Functions.llEmail(address, subject, message);
+        }
+
+        public void llGetNextEmail(string address, string subject)
+        {
+            m_LSL_Functions.llGetNextEmail(address, subject);
+        }
+
+        public string llGetKey()
+        {
+            return m_LSL_Functions.llGetKey();
+        }
+
+        public void llSetBuoyancy(double buoyancy)
+        {
+            m_LSL_Functions.llSetBuoyancy(buoyancy);
+        }
+
+        public void llSetHoverHeight(double height, int water, double tau)
+        {
+            m_LSL_Functions.llSetHoverHeight(height, water, tau);
+        }
+
+        public void llStopHover()
+        {
+            m_LSL_Functions.llStopHover();
+        }
+
+        public void llMinEventDelay(double delay)
+        {
+            m_LSL_Functions.llMinEventDelay(delay);
+        }
+
+        public void llSoundPreload()
+        {
+            m_LSL_Functions.llSoundPreload();
+        }
+
+        public void llRotLookAt(rotation target, double strength, double damping)
+        {
+            m_LSL_Functions.llRotLookAt(target, strength, damping);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public LSL_Types.LSLInteger llStringLength(string str)
+        {
+            return m_LSL_Functions.llStringLength(str);
+        }
+
+        public void llStartAnimation(string anim)
+        {
+            m_LSL_Functions.llStartAnimation(anim);
+        }
+
+        public void llStopAnimation(string anim)
+        {
+            m_LSL_Functions.llStopAnimation(anim);
+        }
+
+        public void llPointAt()
+        {
+            m_LSL_Functions.llPointAt();
+        }
+
+        public void llStopPointAt()
+        {
+            m_LSL_Functions.llStopPointAt();
+        }
+
+        public void llTargetOmega(vector axis, double spinrate, double gain)
+        {
+            m_LSL_Functions.llTargetOmega(axis, spinrate, gain);
+        }
+
+        public LSL_Types.LSLInteger llGetStartParameter()
+        {
+            return m_LSL_Functions.llGetStartParameter();
+        }
+
+        public void llGodLikeRezObject(string inventory, vector pos)
+        {
+            m_LSL_Functions.llGodLikeRezObject(inventory, pos);
+        }
+
+        public void llRequestPermissions(string agent, int perm)
+        {
+            m_LSL_Functions.llRequestPermissions(agent, perm);
+        }
+
+        public string llGetPermissionsKey()
+        {
+            return m_LSL_Functions.llGetPermissionsKey();
+        }
+
+        public LSL_Types.LSLInteger llGetPermissions()
+        {
+            return m_LSL_Functions.llGetPermissions();
+        }
+
+        public LSL_Types.LSLInteger llGetLinkNumber()
+        {
+            return m_LSL_Functions.llGetLinkNumber();
+        }
+
+        public void llSetLinkColor(int linknumber, vector color, int face)
+        {
+            m_LSL_Functions.llSetLinkColor(linknumber, color, face);
+        }
+
+        public void llCreateLink(string target, int parent)
+        {
+            m_LSL_Functions.llCreateLink(target, parent);
+        }
+
+        public void llBreakLink(int linknum)
+        {
+            m_LSL_Functions.llBreakLink(linknum);
+        }
+
+        public void llBreakAllLinks()
+        {
+            m_LSL_Functions.llBreakAllLinks();
+        }
+
+        public string llGetLinkKey(int linknum)
+        {
+            return m_LSL_Functions.llGetLinkKey(linknum);
+        }
+
+        public string llGetLinkName(int linknum)
+        {
+            return m_LSL_Functions.llGetLinkName(linknum);
+        }
+
+        public LSL_Types.LSLInteger llGetInventoryNumber(int type)
+        {
+            return m_LSL_Functions.llGetInventoryNumber(type);
+        }
+
+        public string llGetInventoryName(int type, int number)
+        {
+            return m_LSL_Functions.llGetInventoryName(type, number);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public void llSetScriptState(string name, int run)
+        {
+            m_LSL_Functions.llSetScriptState(name, run);
+        }
+
+        public double llGetEnergy()
+        {
+            return m_LSL_Functions.llGetEnergy();
+        }
+
+        public void llGiveInventory(string destination, string inventory)
+        {
+            m_LSL_Functions.llGiveInventory(destination, inventory);
+        }
+
+        public void llRemoveInventory(string item)
+        {
+            m_LSL_Functions.llRemoveInventory(item);
+        }
+
+        public void llSetText(string text, vector color, double alpha)
+        {
+            m_LSL_Functions.llSetText(text, color, alpha);
+        }
+
+        public double llWater(vector offset)
+        {
+            return m_LSL_Functions.llWater(offset);
+        }
+
+        public void llPassTouches(int pass)
+        {
+            m_LSL_Functions.llPassTouches(pass);
+        }
+
+        public string llRequestAgentData(string id, int data)
+        {
+            return m_LSL_Functions.llRequestAgentData(id, data);
+        }
+
+        public string llRequestInventoryData(string name)
+        {
+            return m_LSL_Functions.llRequestInventoryData(name);
+        }
+
+        public void llSetDamage(double damage)
+        {
+            m_LSL_Functions.llSetDamage(damage);
+        }
+
+        public void llTeleportAgentHome(string agent)
+        {
+            m_LSL_Functions.llTeleportAgentHome(agent);
+        }
+
+        public void llModifyLand(int action, int brush)
+        {
+            m_LSL_Functions.llModifyLand(action, brush);
+        }
+
+        public void llCollisionSound(string impact_sound, double impact_volume)
+        {
+            m_LSL_Functions.llCollisionSound(impact_sound, impact_volume);
+        }
+
+        public void llCollisionSprite(string impact_sprite)
+        {
+            m_LSL_Functions.llCollisionSprite(impact_sprite);
+        }
+
+        public string llGetAnimation(string id)
+        {
+            return m_LSL_Functions.llGetAnimation(id);
+        }
+
+        public void llResetScript()
+        {
+            m_LSL_Functions.llResetScript();
+        }
+
+        public void llMessageLinked(int linknum, int num, string str, string id)
+        {
+            m_LSL_Functions.llMessageLinked(linknum, num, str, id);
+        }
+
+        public void llPushObject(string target, vector impulse, vector ang_impulse, int local)
+        {
+            m_LSL_Functions.llPushObject(target, impulse, ang_impulse, local);
+        }
+
+        public void llPassCollisions(int pass)
+        {
+            m_LSL_Functions.llPassCollisions(pass);
+        }
+
+        public string llGetScriptName()
+        {
+            return m_LSL_Functions.llGetScriptName();
+        }
+
+        public LSL_Types.LSLInteger llGetNumberOfSides()
+        {
+            return m_LSL_Functions.llGetNumberOfSides();
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public rotation llAxisAngle2Rot(vector axis, double angle)
+        {
+            return m_LSL_Functions.llAxisAngle2Rot(axis, angle);
+        }
+
+        public vector llRot2Axis(rotation rot)
+        {
+            return m_LSL_Functions.llRot2Axis(rot);
+        }
+
+        public double llRot2Angle(rotation rot)
+        {
+            return m_LSL_Functions.llRot2Angle(rot);
+        }
+
+        public double llAcos(double val)
+        {
+            return m_LSL_Functions.llAcos(val);
+        }
+
+        public double llAsin(double val)
+        {
+            return m_LSL_Functions.llAsin(val);
+        }
+
+        public double llAngleBetween(rotation a, rotation b)
+        {
+            return m_LSL_Functions.llAngleBetween(a, b);
+        }
+
+        public string llGetInventoryKey(string name)
+        {
+            return m_LSL_Functions.llGetInventoryKey(name);
+        }
+
+        public void llAllowInventoryDrop(int add)
+        {
+            m_LSL_Functions.llAllowInventoryDrop(add);
+        }
+
+        public vector llGetSunDirection()
+        {
+            return m_LSL_Functions.llGetSunDirection();
+        }
+
+        public vector llGetTextureOffset(int face)
+        {
+            return m_LSL_Functions.llGetTextureOffset(face);
+        }
+
+        public vector llGetTextureScale(int side)
+        {
+            return m_LSL_Functions.llGetTextureScale(side);
+        }
+
+        public double llGetTextureRot(int side)
+        {
+            return m_LSL_Functions.llGetTextureRot(side);
+        }
+
+        public LSL_Types.LSLInteger llSubStringIndex(string source, string pattern)
+        {
+            return m_LSL_Functions.llSubStringIndex(source, pattern);
+        }
+
+        public string llGetOwnerKey(string id)
+        {
+            return m_LSL_Functions.llGetOwnerKey(id);
+        }
+
+        public vector llGetCenterOfMass()
+        {
+            return m_LSL_Functions.llGetCenterOfMass();
+        }
+
+        public LSL_Types.list llListSort(LSL_Types.list src, int stride, int ascending)
+        {
+            return m_LSL_Functions.llListSort(src, stride, ascending);
+        }
+
+        public LSL_Types.LSLInteger llGetListLength(LSL_Types.list src)
+        {
+            return m_LSL_Functions.llGetListLength(src);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public LSL_Types.LSLInteger llList2Integer(LSL_Types.list src, int index)
+        {
+            return m_LSL_Functions.llList2Integer(src, index);
+        }
+
+        public string llList2String(LSL_Types.list src, int index)
+        {
+            return m_LSL_Functions.llList2String(src, index);
+        }
+
+        public string llList2Key(LSL_Types.list src, int index)
+        {
+            return m_LSL_Functions.llList2Key(src, index);
+        }
+
+        public vector llList2Vector(LSL_Types.list src, int index)
+        {
+            return m_LSL_Functions.llList2Vector(src, index);
+        }
+
+        public rotation llList2Rot(LSL_Types.list src, int index)
+        {
+            return m_LSL_Functions.llList2Rot(src, index);
+        }
+
+        public LSL_Types.list llList2List(LSL_Types.list src, int start, int end)
+        {
+            return m_LSL_Functions.llList2List(src, start, end);
+        }
+
+        public LSL_Types.list llDeleteSubList(LSL_Types.list src, int start, int end)
+        {
+            return m_LSL_Functions.llDeleteSubList(src, start, end);
+        }
+
+        public LSL_Types.LSLInteger llGetListEntryType(LSL_Types.list src, int index)
+        {
+            return m_LSL_Functions.llGetListEntryType(src, index);
+        }
+
+        public string llList2CSV(LSL_Types.list src)
+        {
+            return m_LSL_Functions.llList2CSV(src);
+        }
+
+        public LSL_Types.list llCSV2List(string src)
+        {
+            return m_LSL_Functions.llCSV2List(src);
+        }
+
+        public LSL_Types.list llListRandomize(LSL_Types.list src, int stride)
+        {
+            return m_LSL_Functions.llListRandomize(src, stride);
+        }
+
+        public LSL_Types.list llList2ListStrided(LSL_Types.list src, int start, int end, int stride)
+        {
+            return m_LSL_Functions.llList2ListStrided(src, start, end, stride);
+        }
+
+        public vector llGetRegionCorner()
+        {
+            return m_LSL_Functions.llGetRegionCorner();
+        }
+
+        public LSL_Types.list llListInsertList(LSL_Types.list dest, LSL_Types.list src, int start)
+        {
+            return m_LSL_Functions.llListInsertList(dest, src, start);
+        }
+
+        public LSL_Types.LSLInteger llListFindList(LSL_Types.list src, LSL_Types.list test)
+        {
+            return m_LSL_Functions.llListFindList(src, test);
+        }
+
+        public string llGetObjectName()
+        {
+            return m_LSL_Functions.llGetObjectName();
+        }
+
+        public void llSetObjectName(string name)
+        {
+            m_LSL_Functions.llSetObjectName(name);
+        }
+
+        public string llGetDate()
+        {
+            return m_LSL_Functions.llGetDate();
+        }
+
+        public LSL_Types.LSLInteger llEdgeOfWorld(vector pos, vector dir)
+        {
+            return m_LSL_Functions.llEdgeOfWorld(pos, dir);
+        }
+
+        public LSL_Types.LSLInteger llGetAgentInfo(string id)
+        {
+            return m_LSL_Functions.llGetAgentInfo(id);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public void llAdjustSoundVolume(double volume)
+        {
+            m_LSL_Functions.llAdjustSoundVolume(volume);
+        }
+
+        public void llSetSoundQueueing(int queue)
+        {
+            m_LSL_Functions.llSetSoundQueueing(queue);
+        }
+
+        public void llSetSoundRadius(double radius)
+        {
+            m_LSL_Functions.llSetSoundRadius(radius);
+        }
+
+        public string llKey2Name(string id)
+        {
+            return m_LSL_Functions.llKey2Name(id);
+        }
+
+        public void llSetTextureAnim(int mode, int face, int sizex, int sizey, double start, double length, double rate)
+        {
+            m_LSL_Functions.llSetTextureAnim(mode, face, sizex, sizey, start, length, rate);
+        }
+
+        public void llTriggerSoundLimited(string sound, double volume, vector top_north_east, vector bottom_south_west)
+        {
+            m_LSL_Functions.llTriggerSoundLimited(sound, volume, top_north_east, bottom_south_west);
+        }
+
+        public void llEjectFromLand(string pest)
+        {
+            m_LSL_Functions.llEjectFromLand(pest);
+        }
+
+        public LSL_Types.list llParseString2List(string str, LSL_Types.list separators, LSL_Types.list spacers)
+        {
+            return m_LSL_Functions.llParseString2List(str,separators,spacers);
+        }
+
+        public LSL_Types.LSLInteger llOverMyLand(string id)
+        {
+            return m_LSL_Functions.llOverMyLand(id);
+        }
+
+        public string llGetLandOwnerAt(vector pos)
+        {
+            return m_LSL_Functions.llGetLandOwnerAt(pos);
+        }
+
+        public string llGetNotecardLine(string name, int line)
+        {
+            return m_LSL_Functions.llGetNotecardLine(name, line);
+        }
+
+        public vector llGetAgentSize(string id)
+        {
+            return m_LSL_Functions.llGetAgentSize(id);
+        }
+
+        public LSL_Types.LSLInteger llSameGroup(string agent)
+        {
+            return m_LSL_Functions.llSameGroup(agent);
+        }
+
+        public void llUnSit(string id)
+        {
+            m_LSL_Functions.llUnSit(id);
+        }
+
+        public vector llGroundSlope(vector offset)
+        {
+            return m_LSL_Functions.llGroundSlope(offset);
+        }
+
+        public vector llGroundNormal(vector offset)
+        {
+            return m_LSL_Functions.llGroundNormal(offset);
+        }
+
+        public vector llGroundContour(vector offset)
+        {
+            return m_LSL_Functions.llGroundContour(offset);
+        }
+
+        public LSL_Types.LSLInteger llGetAttached()
+        {
+            return m_LSL_Functions.llGetAttached();
+        }
+
+        public LSL_Types.LSLInteger llGetFreeMemory()
+        {
+            return m_LSL_Functions.llGetFreeMemory();
+        }
+
+        public string llGetRegionName()
+        {
+            return m_LSL_Functions.llGetRegionName();
+        }
+
+        public double llGetRegionTimeDilation()
+        {
+            return m_LSL_Functions.llGetRegionTimeDilation();
+        }
+
+        public double llGetRegionFPS()
+        {
+            return m_LSL_Functions.llGetRegionFPS();
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public void llParticleSystem(LSL_Types.list rules)
+        {
+            m_LSL_Functions.llParticleSystem(rules);
+        }
+
+        public void llGroundRepel(double height, int water, double tau)
+        {
+            m_LSL_Functions.llGroundRepel(height, water, tau);
+        }
+
+        public void llGiveInventoryList(string destination, string category, LSL_Types.list inventory)
+        {
+            m_LSL_Functions.llGiveInventoryList(destination, category, inventory);
+        }
+
+        public void llSetVehicleType(int type)
+        {
+            m_LSL_Functions.llSetVehicleType(type);
+        }
+
+        public void llSetVehicledoubleParam(int param, double value)
+        {
+            m_LSL_Functions.llSetVehicledoubleParam(param, value);
+        }
+
+        public void llSetVehicleFloatParam(int param, float value)
+        {
+            m_LSL_Functions.llSetVehicleFloatParam(param, value);
+        }
+
+        public void llSetVehicleVectorParam(int param, vector vec)
+        {
+            m_LSL_Functions.llSetVehicleVectorParam(param, vec);
+        }
+
+        public void llSetVehicleRotationParam(int param, rotation rot)
+        {
+            m_LSL_Functions.llSetVehicleRotationParam(param, rot);
+        }
+
+        public void llSetVehicleFlags(int flags)
+        {
+            m_LSL_Functions.llSetVehicleFlags(flags);
+        }
+
+        public void llRemoveVehicleFlags(int flags)
+        {
+            m_LSL_Functions.llRemoveVehicleFlags(flags);
+        }
+
+        public void llSitTarget(vector offset, rotation rot)
+        {
+            m_LSL_Functions.llSitTarget(offset, rot);
+        }
+
+        public string llAvatarOnSitTarget()
+        {
+            return m_LSL_Functions.llAvatarOnSitTarget();
+        }
+
+        public void llAddToLandPassList(string avatar, double hours)
+        {
+            m_LSL_Functions.llAddToLandPassList(avatar, hours);
+        }
+
+        public void llSetTouchText(string text)
+        {
+            m_LSL_Functions.llSetTouchText(text);
+        }
+
+        public void llSetSitText(string text)
+        {
+            m_LSL_Functions.llSetSitText(text);
+        }
+
+        public void llSetCameraEyeOffset(vector offset)
+        {
+            m_LSL_Functions.llSetCameraEyeOffset(offset);
+        }
+
+        public void llSetCameraAtOffset(vector offset)
+        {
+            m_LSL_Functions.llSetCameraAtOffset(offset);
+        }
+
+        public string llDumpList2String(LSL_Types.list src, string seperator)
+        {
+            return m_LSL_Functions.llDumpList2String(src, seperator);
+        }
+
+        public LSL_Types.LSLInteger llScriptDanger(vector pos)
+        {
+            return m_LSL_Functions.llScriptDanger(pos);
+        }
+
+        public void llDialog(string avatar, string message, LSL_Types.list buttons, int chat_channel)
+        {
+            m_LSL_Functions.llDialog(avatar, message, buttons, chat_channel);
+        }
+
+        public void llVolumeDetect(int detect)
+        {
+            m_LSL_Functions.llVolumeDetect(detect);
+        }
+
+        public void llResetOtherScript(string name)
+        {
+            m_LSL_Functions.llResetOtherScript(name);
+        }
+
+        public LSL_Types.LSLInteger llGetScriptState(string name)
+        {
+            return m_LSL_Functions.llGetScriptState(name);
+        }
+
+        public void llRemoteLoadScript()
+        {
+            m_LSL_Functions.llRemoteLoadScript();
+        }
+
+        public void llSetRemoteScriptAccessPin(int pin)
+        {
+            m_LSL_Functions.llSetRemoteScriptAccessPin(pin);
+        }
+
+        public void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param)
+        {
+            m_LSL_Functions.llRemoteLoadScriptPin(target, name, pin, running, start_param);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public void llOpenRemoteDataChannel()
+        {
+            m_LSL_Functions.llOpenRemoteDataChannel();
+        }
+
+        public string llSendRemoteData(string channel, string dest, int idata, string sdata)
+        {
+            return m_LSL_Functions.llSendRemoteData(channel, dest, idata, sdata);
+        }
+
+        public void llRemoteDataReply(string channel, string message_id, string sdata, int idata)
+        {
+            m_LSL_Functions.llRemoteDataReply(channel, message_id, sdata, idata);
+        }
+
+        public void llCloseRemoteDataChannel(string channel)
+        {
+            m_LSL_Functions.llCloseRemoteDataChannel(channel);
+        }
+
+        public string llMD5String(string src, int nonce)
+        {
+            return m_LSL_Functions.llMD5String(src, nonce);
+        }
+
+        public void llSetPrimitiveParams(LSL_Types.list rules)
+        {
+            m_LSL_Functions.llSetPrimitiveParams(rules);
+        }
+
+        public void llSetLinkPrimitiveParams(int linknumber, LSL_Types.list rules)
+        {
+            m_LSL_Functions.llSetLinkPrimitiveParams(linknumber, rules);
+        }
+        public string llStringToBase64(string str)
+        {
+            return m_LSL_Functions.llStringToBase64(str);
+        }
+
+        public string llBase64ToString(string str)
+        {
+            return m_LSL_Functions.llBase64ToString(str);
+        }
+
+        public void llXorBase64Strings()
+        {
+            m_LSL_Functions.llXorBase64Strings();
+        }
+
+        public void llRemoteDataSetRegion()
+        {
+            m_LSL_Functions.llRemoteDataSetRegion();
+        }
+
+        public double llLog10(double val)
+        {
+            return m_LSL_Functions.llLog10(val);
+        }
+
+        public double llLog(double val)
+        {
+            return m_LSL_Functions.llLog(val);
+        }
+
+        public LSL_Types.list llGetAnimationList(string id)
+        {
+            return m_LSL_Functions.llGetAnimationList(id);
+        }
+
+        public void llSetParcelMusicURL(string url)
+        {
+            m_LSL_Functions.llSetParcelMusicURL(url);
+        }
+
+        public vector llGetRootPosition()
+        {
+            return m_LSL_Functions.llGetRootPosition();
+        }
+
+        public rotation llGetRootRotation()
+        {
+            return m_LSL_Functions.llGetRootRotation();
+        }
+
+        public string llGetObjectDesc()
+        {
+            return m_LSL_Functions.llGetObjectDesc();
+        }
+
+        public void llSetObjectDesc(string desc)
+        {
+            m_LSL_Functions.llSetObjectDesc(desc);
+        }
+
+        public string llGetCreator()
+        {
+            return m_LSL_Functions.llGetCreator();
+        }
+
+        public string llGetTimestamp()
+        {
+            return m_LSL_Functions.llGetTimestamp();
+        }
+
+        public void llSetLinkAlpha(int linknumber, double alpha, int face)
+        {
+            m_LSL_Functions.llSetLinkAlpha(linknumber, alpha, face);
+        }
+
+        public LSL_Types.LSLInteger llGetNumberOfPrims()
+        {
+            return m_LSL_Functions.llGetNumberOfPrims();
+        }
+
+        public string llGetNumberOfNotecardLines(string name)
+        {
+            return m_LSL_Functions.llGetNumberOfNotecardLines(name);
+        }
+
+        public LSL_Types.list llGetBoundingBox(string obj)
+        {
+            return m_LSL_Functions.llGetBoundingBox(obj);
+        }
+
+        public vector llGetGeometricCenter()
+        {
+            return m_LSL_Functions.llGetGeometricCenter();
+        }
+
+        public LSL_Types.list llGetPrimitiveParams(LSL_Types.list rules)
+        {
+            return m_LSL_Functions.llGetPrimitiveParams(rules);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public string llIntegerToBase64(int number)
+        {
+            return m_LSL_Functions.llIntegerToBase64(number);
+        }
+
+        public LSL_Types.LSLInteger llBase64ToInteger(string str)
+        {
+            return m_LSL_Functions.llBase64ToInteger(str);
+        }
+
+        public double llGetGMTclock()
+        {
+            return m_LSL_Functions.llGetGMTclock();
+        }
+
+        public string llGetSimulatorHostname()
+        {
+            return m_LSL_Functions.llGetSimulatorHostname();
+        }
+
+        public void llSetLocalRot(rotation rot)
+        {
+            m_LSL_Functions.llSetLocalRot(rot);
+        }
+
+        public LSL_Types.list llParseStringKeepNulls(string src, LSL_Types.list seperators, LSL_Types.list spacers)
+        {
+            return m_LSL_Functions.llParseStringKeepNulls(src, seperators, spacers);
+        }
+
+        public void llRezAtRoot(string inventory, vector position, vector velocity, rotation rot, int param)
+        {
+            m_LSL_Functions.llRezAtRoot(inventory, position, velocity, rot, param);
+        }
+
+        public LSL_Types.LSLInteger llGetObjectPermMask(int mask)
+        {
+            return m_LSL_Functions.llGetObjectPermMask(mask);
+        }
+
+        public void llSetObjectPermMask(int mask, int value)
+        {
+            m_LSL_Functions.llSetObjectPermMask(mask, value);
+        }
+
+        public LSL_Types.LSLInteger llGetInventoryPermMask(string item, int mask)
+        {
+            return m_LSL_Functions.llGetInventoryPermMask(item, mask);
+        }
+
+        public void llSetInventoryPermMask(string item, int mask, int value)
+        {
+            m_LSL_Functions.llSetInventoryPermMask(item, mask, value);
+        }
+
+        public string llGetInventoryCreator(string item)
+        {
+            return m_LSL_Functions.llGetInventoryCreator(item);
+        }
+
+        public void llOwnerSay(string msg)
+        {
+            m_LSL_Functions.llOwnerSay(msg);
+        }
+
+        public string llRequestSimulatorData(string simulator, int data)
+        {
+            return m_LSL_Functions.llRequestSimulatorData(simulator, data);
+        }
+
+        public void llForceMouselook(int mouselook)
+        {
+            m_LSL_Functions.llForceMouselook(mouselook);
+        }
+
+        public double llGetObjectMass(string id)
+        {
+            return m_LSL_Functions.llGetObjectMass(id);
+        }
+
+        public LSL_Types.list llListReplaceList(LSL_Types.list dest, LSL_Types.list src, int start, int end)
+        {
+            return m_LSL_Functions.llListReplaceList(dest, src, start, end);
+        }
+
+        public void llLoadURL(string avatar_id, string message, string url)
+        {
+            m_LSL_Functions.llLoadURL(avatar_id, message, url);
+        }
+
+        public void llParcelMediaCommandList(LSL_Types.list commandList)
+        {
+            m_LSL_Functions.llParcelMediaCommandList(commandList);
+        }
+
+        public void llParcelMediaQuery()
+        {
+            m_LSL_Functions.llParcelMediaQuery();
+        }
+
+        public LSL_Types.LSLInteger llModPow(int a, int b, int c)
+        {
+            return m_LSL_Functions.llModPow(a, b, c);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public LSL_Types.LSLInteger llGetInventoryType(string name)
+        {
+            return m_LSL_Functions.llGetInventoryType(name);
+        }
+
+        public void llSetPayPrice(int price, LSL_Types.list quick_pay_buttons)
+        {
+            m_LSL_Functions.llSetPayPrice(price, quick_pay_buttons);
+        }
+
+        public vector llGetCameraPos()
+        {
+            return m_LSL_Functions.llGetCameraPos();
+        }
+
+        public rotation llGetCameraRot()
+        {
+            return m_LSL_Functions.llGetCameraRot();
+        }
+
+        public void llSetPrimURL()
+        {
+            m_LSL_Functions.llSetPrimURL();
+        }
+
+        public void llRefreshPrimURL()
+        {
+            m_LSL_Functions.llRefreshPrimURL();
+        }
+
+        public string llEscapeURL(string url)
+        {
+            return m_LSL_Functions.llEscapeURL(url);
+        }
+
+        public string llUnescapeURL(string url)
+        {
+            return m_LSL_Functions.llUnescapeURL(url);
+        }
+
+        public void llMapDestination(string simname, vector pos, vector look_at)
+        {
+            m_LSL_Functions.llMapDestination(simname, pos, look_at);
+        }
+
+        public void llAddToLandBanList(string avatar, double hours)
+        {
+            m_LSL_Functions.llAddToLandBanList(avatar, hours);
+        }
+
+        public void llRemoveFromLandPassList(string avatar)
+        {
+            m_LSL_Functions.llRemoveFromLandPassList(avatar);
+        }
+
+        public void llRemoveFromLandBanList(string avatar)
+        {
+            m_LSL_Functions.llRemoveFromLandBanList(avatar);
+        }
+
+        public void llSetCameraParams(LSL_Types.list rules)
+        {
+            m_LSL_Functions.llSetCameraParams(rules);
+        }
+
+        public void llClearCameraParams()
+        {
+            m_LSL_Functions.llClearCameraParams();
+        }
+
+        public double llListStatistics(int operation, LSL_Types.list src)
+        {
+            return m_LSL_Functions.llListStatistics(operation, src);
+        }
+
+        public LSL_Types.LSLInteger llGetUnixTime()
+        {
+            return m_LSL_Functions.llGetUnixTime();
+        }
+
+        public LSL_Types.LSLInteger llGetParcelFlags(vector pos)
+        {
+            return m_LSL_Functions.llGetParcelFlags(pos);
+        }
+
+        public LSL_Types.LSLInteger llGetRegionFlags()
+        {
+            return m_LSL_Functions.llGetRegionFlags();
+        }
+
+        public string llXorBase64StringsCorrect(string str1, string str2)
+        {
+            return m_LSL_Functions.llXorBase64StringsCorrect(str1, str2);
+        }
+
+        public string llHTTPRequest(string url, LSL_Types.list parameters, string body)
+        {
+            return m_LSL_Functions.llHTTPRequest(url, parameters, body);
+        }
+
+        public void llResetLandBanList()
+        {
+            m_LSL_Functions.llResetLandBanList();
+        }
+
+        public void llResetLandPassList()
+        {
+            m_LSL_Functions.llResetLandPassList();
+        }
+
+        public LSL_Types.LSLInteger llGetParcelPrimCount(vector pos, int category, int sim_wide)
+        {
+            return m_LSL_Functions.llGetParcelPrimCount(pos, category, sim_wide);
+        }
+
+        public LSL_Types.list llGetParcelPrimOwners(vector pos)
+        {
+            return m_LSL_Functions.llGetParcelPrimOwners(pos);
+        }
+
+        public LSL_Types.LSLInteger llGetObjectPrimCount(string object_id)
+        {
+            return m_LSL_Functions.llGetObjectPrimCount(object_id);
+        }
+
+        //
+        // DO NOT MODIFY HERE: MODIFY IN LSL_BuiltIn_Commands.cs
+        //
+        public LSL_Types.LSLInteger llGetParcelMaxPrims(vector pos, int sim_wide)
+        {
+            return m_LSL_Functions.llGetParcelMaxPrims(pos, sim_wide);
+        }
+
+        public LSL_Types.list llGetParcelDetails(vector pos, LSL_Types.list param)
+        {
+            return m_LSL_Functions.llGetParcelDetails(pos, param);
+        }
+
+        public void llSetLinkTexture(int linknumber, string texture, int face)
+        {
+            m_LSL_Functions.llSetLinkTexture(linknumber, texture, face);
+        }
+
+        public string llStringTrim(string src, int type)
+        {
+            return m_LSL_Functions.llStringTrim(src, type);
+        }
+
+        public LSL_Types.list llGetObjectDetails(string id, LSL_Types.list args)
+        {
+            return m_LSL_Functions.llGetObjectDetails(id, args);
+        }
+
+        public double llList2Float(LSL_Types.list src, int index)
+        {
+            return m_LSL_Functions.llList2Float(src, index);
+        }
+
+        // LSL CONSTANTS
+        public const int TRUE = 1;
+        public const int FALSE = 0;
+
+        public const int STATUS_PHYSICS = 1;
+        public const int STATUS_ROTATE_X = 2;
+        public const int STATUS_ROTATE_Y = 4;
+        public const int STATUS_ROTATE_Z = 8;
+        public const int STATUS_PHANTOM = 16;
+        public const int STATUS_SANDBOX = 32;
+        public const int STATUS_BLOCK_GRAB = 64;
+        public const int STATUS_DIE_AT_EDGE = 128;
+        public const int STATUS_RETURN_AT_EDGE = 256;
+        public const int STATUS_CAST_SHADOWS = 512;
+
+        public const int AGENT = 1;
+        public const int ACTIVE = 2;
+        public const int PASSIVE = 4;
+        public const int SCRIPTED = 8;
+
+        public const int CONTROL_FWD = 1;
+        public const int CONTROL_BACK = 2;
+        public const int CONTROL_LEFT = 4;
+        public const int CONTROL_RIGHT = 8;
+        public const int CONTROL_UP = 16;
+        public const int CONTROL_DOWN = 32;
+        public const int CONTROL_ROT_LEFT = 256;
+        public const int CONTROL_ROT_RIGHT = 512;
+        public const int CONTROL_LBUTTON = 268435456;
+        public const int CONTROL_ML_LBUTTON = 1073741824;
+
+        //Permissions
+        public const int PERMISSION_DEBIT = 2;
+        public const int PERMISSION_TAKE_CONTROLS = 4;
+        public const int PERMISSION_REMAP_CONTROLS = 8;
+        public const int PERMISSION_TRIGGER_ANIMATION = 16;
+        public const int PERMISSION_ATTACH = 32;
+        public const int PERMISSION_RELEASE_OWNERSHIP = 64;
+        public const int PERMISSION_CHANGE_LINKS = 128;
+        public const int PERMISSION_CHANGE_JOINTS = 256;
+        public const int PERMISSION_CHANGE_PERMISSIONS = 512;
+        public const int PERMISSION_TRACK_CAMERA = 1024;
+
+        public const int AGENT_FLYING = 1;
+        public const int AGENT_ATTACHMENTS = 2;
+        public const int AGENT_SCRIPTED = 4;
+        public const int AGENT_MOUSELOOK = 8;
+        public const int AGENT_SITTING = 16;
+        public const int AGENT_ON_OBJECT = 32;
+        public const int AGENT_AWAY = 64;
+        public const int AGENT_WALKING = 128;
+        public const int AGENT_IN_AIR = 256;
+        public const int AGENT_TYPING = 512;
+        public const int AGENT_CROUCHING = 1024;
+        public const int AGENT_BUSY = 2048;
+        public const int AGENT_ALWAYS_RUN = 4096;
+
+        //Particle Systems
+        public const int PSYS_PART_INTERP_COLOR_MASK = 1;
+        public const int PSYS_PART_INTERP_SCALE_MASK = 2;
+        public const int PSYS_PART_BOUNCE_MASK = 4;
+        public const int PSYS_PART_WIND_MASK = 8;
+        public const int PSYS_PART_FOLLOW_SRC_MASK = 16;
+        public const int PSYS_PART_FOLLOW_VELOCITY_MASK = 32;
+        public const int PSYS_PART_TARGET_POS_MASK = 64;
+        public const int PSYS_PART_TARGET_LINEAR_MASK = 128;
+        public const int PSYS_PART_EMISSIVE_MASK = 256;
+        public const int PSYS_PART_FLAGS = 0;
+        public const int PSYS_PART_START_COLOR = 1;
+        public const int PSYS_PART_START_ALPHA = 2;
+        public const int PSYS_PART_END_COLOR = 3;
+        public const int PSYS_PART_END_ALPHA = 4;
+        public const int PSYS_PART_START_SCALE = 5;
+        public const int PSYS_PART_END_SCALE = 6;
+        public const int PSYS_PART_MAX_AGE = 7;
+        public const int PSYS_SRC_ACCEL = 8;
+        public const int PSYS_SRC_PATTERN = 9;
+        public const int PSYS_SRC_INNERANGLE = 10;
+        public const int PSYS_SRC_OUTERANGLE = 11;
+        public const int PSYS_SRC_TEXTURE = 12;
+        public const int PSYS_SRC_BURST_RATE = 13;
+        public const int PSYS_SRC_BURST_PART_COUNT = 15;
+        public const int PSYS_SRC_BURST_RADIUS = 16;
+        public const int PSYS_SRC_BURST_SPEED_MIN = 17;
+        public const int PSYS_SRC_BURST_SPEED_MAX = 18;
+        public const int PSYS_SRC_MAX_AGE = 19;
+        public const int PSYS_SRC_TARGET_KEY = 20;
+        public const int PSYS_SRC_OMEGA = 21;
+        public const int PSYS_SRC_ANGLE_BEGIN = 22;
+        public const int PSYS_SRC_ANGLE_END = 23;
+        public const int PSYS_SRC_PATTERN_DROP = 1;
+        public const int PSYS_SRC_PATTERN_EXPLODE = 2;
+        public const int PSYS_SRC_PATTERN_ANGLE = 4;
+        public const int PSYS_SRC_PATTERN_ANGLE_CONE = 8;
+        public const int PSYS_SRC_PATTERN_ANGLE_CONE_EMPTY = 16;
+
+        public const int VEHICLE_TYPE_NONE = 0;
+        public const int VEHICLE_TYPE_SLED = 1;
+        public const int VEHICLE_TYPE_CAR = 2;
+        public const int VEHICLE_TYPE_BOAT = 3;
+        public const int VEHICLE_TYPE_AIRPLANE = 4;
+        public const int VEHICLE_TYPE_BALLOON = 5;
+        public const int VEHICLE_LINEAR_FRICTION_TIMESCALE = 16;
+        public const int VEHICLE_ANGULAR_FRICTION_TIMESCALE = 17;
+        public const int VEHICLE_LINEAR_MOTOR_DIRECTION = 18;
+        public const int VEHICLE_LINEAR_MOTOR_OFFSET = 20;
+        public const int VEHICLE_ANGULAR_MOTOR_DIRECTION = 19;
+        public const int VEHICLE_HOVER_HEIGHT = 24;
+        public const int VEHICLE_HOVER_EFFICIENCY = 25;
+        public const int VEHICLE_HOVER_TIMESCALE = 26;
+        public const int VEHICLE_BUOYANCY = 27;
+        public const int VEHICLE_LINEAR_DEFLECTION_EFFICIENCY = 28;
+        public const int VEHICLE_LINEAR_DEFLECTION_TIMESCALE = 29;
+        public const int VEHICLE_LINEAR_MOTOR_TIMESCALE = 30;
+        public const int VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE = 31;
+        public const int VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY = 32;
+        public const int VEHICLE_ANGULAR_DEFLECTION_TIMESCALE = 33;
+        public const int VEHICLE_ANGULAR_MOTOR_TIMESCALE = 34;
+        public const int VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE = 35;
+        public const int VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY = 36;
+        public const int VEHICLE_VERTICAL_ATTRACTION_TIMESCALE = 37;
+        public const int VEHICLE_BANKING_EFFICIENCY = 38;
+        public const int VEHICLE_BANKING_MIX = 39;
+        public const int VEHICLE_BANKING_TIMESCALE = 40;
+        public const int VEHICLE_REFERENCE_FRAME = 44;
+        public const int VEHICLE_FLAG_NO_DEFLECTION_UP = 1;
+        public const int VEHICLE_FLAG_LIMIT_ROLL_ONLY = 2;
+        public const int VEHICLE_FLAG_HOVER_WATER_ONLY = 4;
+        public const int VEHICLE_FLAG_HOVER_TERRAIN_ONLY = 8;
+        public const int VEHICLE_FLAG_HOVER_GLOBAL_HEIGHT = 16;
+        public const int VEHICLE_FLAG_HOVER_UP_ONLY = 32;
+        public const int VEHICLE_FLAG_LIMIT_MOTOR_UP = 64;
+        public const int VEHICLE_FLAG_MOUSELOOK_STEER = 128;
+        public const int VEHICLE_FLAG_MOUSELOOK_BANK = 256;
+        public const int VEHICLE_FLAG_CAMERA_DECOUPLED = 512;
+
+        public const int INVENTORY_ALL = -1;
+        public const int INVENTORY_NONE = -1;
+        public const int INVENTORY_TEXTURE = 0;
+        public const int INVENTORY_SOUND = 1;
+        public const int INVENTORY_LANDMARK = 3;
+        public const int INVENTORY_CLOTHING = 5;
+        public const int INVENTORY_OBJECT = 6;
+        public const int INVENTORY_NOTECARD = 7;
+        public const int INVENTORY_SCRIPT = 10;
+        public const int INVENTORY_BODYPART = 13;
+        public const int INVENTORY_ANIMATION = 20;
+        public const int INVENTORY_GESTURE = 21;
+
+        public const int ATTACH_CHEST = 1;
+        public const int ATTACH_HEAD = 2;
+        public const int ATTACH_LSHOULDER = 3;
+        public const int ATTACH_RSHOULDER = 4;
+        public const int ATTACH_LHAND = 5;
+        public const int ATTACH_RHAND = 6;
+        public const int ATTACH_LFOOT = 7;
+        public const int ATTACH_RFOOT = 8;
+        public const int ATTACH_BACK = 9;
+        public const int ATTACH_PELVIS = 10;
+        public const int ATTACH_MOUTH = 11;
+        public const int ATTACH_CHIN = 12;
+        public const int ATTACH_LEAR = 13;
+        public const int ATTACH_REAR = 14;
+        public const int ATTACH_LEYE = 15;
+        public const int ATTACH_REYE = 16;
+        public const int ATTACH_NOSE = 17;
+        public const int ATTACH_RUARM = 18;
+        public const int ATTACH_RLARM = 19;
+        public const int ATTACH_LUARM = 20;
+        public const int ATTACH_LLARM = 21;
+        public const int ATTACH_RHIP = 22;
+        public const int ATTACH_RULEG = 23;
+        public const int ATTACH_RLLEG = 24;
+        public const int ATTACH_LHIP = 25;
+        public const int ATTACH_LULEG = 26;
+        public const int ATTACH_LLLEG = 27;
+        public const int ATTACH_BELLY = 28;
+        public const int ATTACH_RPEC = 29;
+        public const int ATTACH_LPEC = 30;
+
+        public const int LAND_LEVEL = 0;
+        public const int LAND_RAISE = 1;
+        public const int LAND_LOWER = 2;
+        public const int LAND_SMOOTH = 3;
+        public const int LAND_NOISE = 4;
+        public const int LAND_REVERT = 5;
+        public const int LAND_SMALL_BRUSH = 1;
+        public const int LAND_MEDIUM_BRUSH = 2;
+        public const int LAND_LARGE_BRUSH = 3;
+
+        //Agent Dataserver
+        public const int DATA_ONLINE = 1;
+        public const int DATA_NAME = 2;
+        public const int DATA_BORN = 3;
+        public const int DATA_RATING = 4;
+        public const int DATA_SIM_POS = 5;
+        public const int DATA_SIM_STATUS = 6;
+        public const int DATA_SIM_RATING = 7;
+        public const int DATA_PAYINFO = 8;
+
+        public const int ANIM_ON = 1;
+        public const int LOOP = 2;
+        public const int REVERSE = 4;
+        public const int PING_PONG = 8;
+        public const int SMOOTH = 16;
+        public const int ROTATE = 32;
+        public const int SCALE = 64;
+        public const int ALL_SIDES = -1;
+        public const int LINK_SET = -1;
+        public const int LINK_ROOT = 1;
+        public const int LINK_ALL_OTHERS = -2;
+        public const int LINK_ALL_CHILDREN = -3;
+        public const int LINK_THIS = -4;
+        public const int CHANGED_INVENTORY = 1;
+        public const int CHANGED_COLOR = 2;
+        public const int CHANGED_SHAPE = 4;
+        public const int CHANGED_SCALE = 8;
+        public const int CHANGED_TEXTURE = 16;
+        public const int CHANGED_LINK = 32;
+        public const int CHANGED_ALLOWED_DROP = 64;
+        public const int CHANGED_OWNER = 128;
+        public const int TYPE_INVALID = 0;
+        public const int TYPE_INTEGER = 1;
+        public const int TYPE_double = 2;
+        public const int TYPE_STRING = 3;
+        public const int TYPE_KEY = 4;
+        public const int TYPE_VECTOR = 5;
+        public const int TYPE_ROTATION = 6;
+
+        //XML RPC Remote Data Channel
+        public const int REMOTE_DATA_CHANNEL = 1;
+        public const int REMOTE_DATA_REQUEST = 2;
+        public const int REMOTE_DATA_REPLY = 3;
+
+        //llHTTPRequest
+        public const int HTTP_METHOD = 0;
+        public const int HTTP_MIMETYPE = 1;
+        public const int HTTP_BODY_MAXLENGTH = 2;
+        public const int HTTP_VERIFY_CERT = 3;
+
+        public const int PRIM_MATERIAL = 2;
+        public const int PRIM_PHYSICS = 3;
+        public const int PRIM_TEMP_ON_REZ = 4;
+        public const int PRIM_PHANTOM = 5;
+        public const int PRIM_POSITION = 6;
+        public const int PRIM_SIZE = 7;
+        public const int PRIM_ROTATION = 8;
+        public const int PRIM_TYPE = 9;
+        public const int PRIM_TEXTURE = 17;
+        public const int PRIM_COLOR = 18;
+        public const int PRIM_BUMP_SHINY = 19;
+        public const int PRIM_FULLBRIGHT = 20;
+        public const int PRIM_FLEXIBLE = 21;
+        public const int PRIM_TEXGEN = 22;
+        public const int PRIM_CAST_SHADOWS = 24; // Not implemented, here for completeness sake
+        public const int PRIM_POINT_LIGHT = 23; // Huh?
+        public const int PRIM_TEXGEN_DEFAULT = 0;
+        public const int PRIM_TEXGEN_PLANAR = 1;
+
+        public const int PRIM_TYPE_BOX = 0;
+        public const int PRIM_TYPE_CYLINDER = 1;
+        public const int PRIM_TYPE_PRISM = 2;
+        public const int PRIM_TYPE_SPHERE = 3;
+        public const int PRIM_TYPE_TORUS = 4;
+        public const int PRIM_TYPE_TUBE = 5;
+        public const int PRIM_TYPE_RING = 6;
+        public const int PRIM_TYPE_SCULPT = 7;
+
+        public const int PRIM_HOLE_DEFAULT = 0;
+        public const int PRIM_HOLE_CIRCLE = 16;
+        public const int PRIM_HOLE_SQUARE = 32;
+        public const int PRIM_HOLE_TRIANGLE = 48;
+
+        public const int PRIM_MATERIAL_STONE = 0;
+        public const int PRIM_MATERIAL_METAL = 1;
+        public const int PRIM_MATERIAL_GLASS = 2;
+        public const int PRIM_MATERIAL_WOOD = 3;
+        public const int PRIM_MATERIAL_FLESH = 4;
+        public const int PRIM_MATERIAL_PLASTIC = 5;
+        public const int PRIM_MATERIAL_RUBBER = 6;
+        public const int PRIM_MATERIAL_LIGHT = 7;
+
+        public const int PRIM_SHINY_NONE = 0;
+        public const int PRIM_SHINY_LOW = 1;
+        public const int PRIM_SHINY_MEDIUM = 2;
+        public const int PRIM_SHINY_HIGH = 3;
+        public const int PRIM_BUMP_NONE = 0;
+        public const int PRIM_BUMP_BRIGHT = 1;
+        public const int PRIM_BUMP_DARK = 2;
+        public const int PRIM_BUMP_WOOD = 3;
+        public const int PRIM_BUMP_BARK = 4;
+        public const int PRIM_BUMP_BRICKS = 5;
+        public const int PRIM_BUMP_CHECKER = 6;
+        public const int PRIM_BUMP_CONCRETE = 7;
+        public const int PRIM_BUMP_TILE = 8;
+        public const int PRIM_BUMP_STONE = 9;
+        public const int PRIM_BUMP_DISKS = 10;
+        public const int PRIM_BUMP_GRAVEL = 11;
+        public const int PRIM_BUMP_BLOBS = 12;
+        public const int PRIM_BUMP_SIDING = 13;
+        public const int PRIM_BUMP_LARGETILE = 14;
+        public const int PRIM_BUMP_STUCCO = 15;
+        public const int PRIM_BUMP_SUCTION = 16;
+        public const int PRIM_BUMP_WEAVE = 17;
+
+        public const int PRIM_SCULPT_TYPE_SPHERE = 1;
+        public const int PRIM_SCULPT_TYPE_TORUS = 2;
+        public const int PRIM_SCULPT_TYPE_PLANE = 3;
+        public const int PRIM_SCULPT_TYPE_CYLINDER = 4;
+
+        public const int MASK_BASE = 0;
+        public const int MASK_OWNER = 1;
+        public const int MASK_GROUP = 2;
+        public const int MASK_EVERYONE = 3;
+        public const int MASK_NEXT = 4;
+
+        public const int PERM_TRANSFER = 8192;
+        public const int PERM_MODIFY = 16384;
+        public const int PERM_COPY = 32768;
+        public const int PERM_MOVE = 524288;
+        public const int PERM_ALL = 2147483647;
+
+        public const int PARCEL_MEDIA_COMMAND_STOP = 0;
+        public const int PARCEL_MEDIA_COMMAND_PAUSE = 1;
+        public const int PARCEL_MEDIA_COMMAND_PLAY = 2;
+        public const int PARCEL_MEDIA_COMMAND_LOOP = 3;
+        public const int PARCEL_MEDIA_COMMAND_TEXTURE = 4;
+        public const int PARCEL_MEDIA_COMMAND_URL = 5;
+        public const int PARCEL_MEDIA_COMMAND_TIME = 6;
+        public const int PARCEL_MEDIA_COMMAND_AGENT = 7;
+        public const int PARCEL_MEDIA_COMMAND_UNLOAD = 8;
+        public const int PARCEL_MEDIA_COMMAND_AUTO_ALIGN = 9;
+
+        public const int PAY_HIDE = -1;
+        public const int PAY_DEFAULT = -2;
+
+        public const string NULL_KEY = "00000000-0000-0000-0000-000000000000";
+        public const string EOF = "\n\n\n";
+        public const double PI = 3.14159274f;
+        public const double TWO_PI = 6.28318548f;
+        public const double PI_BY_TWO = 1.57079637f;
+        public const double DEG_TO_RAD = 0.01745329238f;
+        public const double RAD_TO_DEG = 57.29578f;
+        public const double SQRT2 = 1.414213538f;
+        public const int STRING_TRIM_HEAD = 1;
+        public const int STRING_TRIM_TAIL = 2;
+        public const int STRING_TRIM = 3;
+        public const int LIST_STAT_RANGE = 0;
+        public const int LIST_STAT_MIN = 1;
+        public const int LIST_STAT_MAX = 2;
+        public const int LIST_STAT_MEAN = 3;
+        public const int LIST_STAT_MEDIAN = 4;
+        public const int LIST_STAT_STD_DEV = 5;
+        public const int LIST_STAT_SUM = 6;
+        public const int LIST_STAT_SUM_SQUARES = 7;
+        public const int LIST_STAT_NUM_COUNT = 8;
+        public const int LIST_STAT_GEOMETRIC_MEAN = 9;
+        public const int LIST_STAT_HARMONIC_MEAN = 100;
+
+        //ParcelPrim Categories
+        public const int PARCEL_COUNT_TOTAL = 0;
+        public const int PARCEL_COUNT_OWNER = 1;
+        public const int PARCEL_COUNT_GROUP = 2;
+        public const int PARCEL_COUNT_OTHER = 3;
+        public const int PARCEL_COUNT_SELECTED = 4;
+        public const int PARCEL_COUNT_TEMP = 5;
+
+        public const int DEBUG_CHANNEL  = 0x7FFFFFFF;
+        public const int PUBLIC_CHANNEL = 0x00000000;
+
+        public const int OBJECT_NAME = 1;
+        public const int OBJECT_DESC = 2;
+        public const int OBJECT_POS = 3;
+        public const int OBJECT_ROT = 4;
+        public const int OBJECT_VELOCITY = 5;
+        public const int OBJECT_OWNER = 6;
+        public const int OBJECT_GROUP = 7;
+        public const int OBJECT_CREATOR = 8;
+
+        // Can not be public const?
+        public vector ZERO_VECTOR = new vector(0.0, 0.0, 0.0);
+        public rotation ZERO_ROTATION = new rotation(0.0, 0, 0.0, 1.0);
+
+
+        //
+        // OSSL
+        //
+        // FIXME: Refactor so we don't need to pull the script engine
+        // into the app domain
+        //
+
+        public void osSetRegionWaterHeight(double height)
+        {
+            m_OSSL_Functions.osSetRegionWaterHeight(height);
+        }
+
+        public double osList2Double(LSL_Types.list src, int index)
+        {
+            return m_OSSL_Functions.osList2Double(src, index);
+        }
+
+        public string osSetDynamicTextureURL(string dynamicID, string contentType, string url, string extraParams,
+                                             int timer)
+        {
+            return m_OSSL_Functions.osSetDynamicTextureURL(dynamicID, contentType, url, extraParams, timer);
+        }
+
+        public string osSetDynamicTextureData(string dynamicID, string contentType, string data, string extraParams,
+                                             int timer)
+        {
+            return m_OSSL_Functions.osSetDynamicTextureData(dynamicID, contentType, data, extraParams, timer);
+        }
+
+        public string osSetDynamicTextureURLBlend(string dynamicID, string contentType, string url, string extraParams,
+                                           int timer, int alpha)
+        {
+            return m_OSSL_Functions.osSetDynamicTextureURLBlend(dynamicID, contentType, url, extraParams, timer, alpha);
+        }
+
+        public string osSetDynamicTextureDataBlend(string dynamicID, string contentType, string data, string extraParams,
+                                             int timer, int alpha)
+        {
+            return m_OSSL_Functions.osSetDynamicTextureDataBlend(dynamicID, contentType, data, extraParams, timer, alpha);
+        }
+
+        public double osTerrainGetHeight(int x, int y)
+        {
+            return m_OSSL_Functions.osTerrainGetHeight(x, y);
+        }
+
+        public int osTerrainSetHeight(int x, int y, double val)
+        {
+            return m_OSSL_Functions.osTerrainSetHeight(x, y, val);
+        }
+
+        public int osRegionRestart(double seconds)
+        {
+            return m_OSSL_Functions.osRegionRestart(seconds);
+        }
+
+        public void osRegionNotice(string msg)
+        {
+            m_OSSL_Functions.osRegionNotice(msg);
+        }
+
+        public bool osConsoleCommand(string Command)
+        {
+            return m_OSSL_Functions.osConsoleCommand(Command);
+        }
+
+        public void osSetParcelMediaURL(string url)
+        {
+            m_OSSL_Functions.osSetParcelMediaURL(url);
+        }
+
+        public void osSetPrimFloatOnWater(int floatYN)
+        {
+            m_OSSL_Functions.osSetPrimFloatOnWater(floatYN);
+        }
+
+        // Animation Functions
+
+        public void osAvatarPlayAnimation(string avatar, string animation)
+        {
+            m_OSSL_Functions.osAvatarPlayAnimation(avatar, animation);
+        }
+
+        public void osAvatarStopAnimation(string avatar, string animation)
+        {
+            m_OSSL_Functions.osAvatarStopAnimation(avatar, animation);
+        }
+
+
+        //Texture Draw functions
+
+        public string osMovePen(string drawList, int x, int y)
+        {
+            return m_OSSL_Functions.osMovePen(drawList, x, y);
+        }
+
+        public string osDrawLine(string drawList, int startX, int startY, int endX, int endY)
+        {
+            return m_OSSL_Functions.osDrawLine(drawList, startX, startY, endX, endY);
+        }
+
+        public string osDrawLine(string drawList, int endX, int endY)
+        {
+            return m_OSSL_Functions.osDrawLine(drawList, endX, endY);
+        }
+
+        public string osDrawText(string drawList, string text)
+        {
+            return m_OSSL_Functions.osDrawText(drawList, text);
+        }
+
+        public string osDrawEllipse(string drawList, int width, int height)
+        {
+            return m_OSSL_Functions.osDrawEllipse(drawList, width, height);
+        }
+
+        public string osDrawRectangle(string drawList, int width, int height)
+        {
+            return m_OSSL_Functions.osDrawRectangle(drawList, width, height);
+        }
+
+        public string osDrawFilledRectangle(string drawList, int width, int height)
+        {
+            return m_OSSL_Functions.osDrawFilledRectangle(drawList, width, height);
+        }
+
+        public string osSetFontSize(string drawList, int fontSize)
+        {
+            return m_OSSL_Functions.osSetFontSize(drawList, fontSize);
+        }
+
+        public string osSetPenSize(string drawList, int penSize)
+        {
+            return m_OSSL_Functions.osSetPenSize(drawList, penSize);
+        }
+
+        public string osSetPenColour(string drawList, string colour)
+        {
+            return m_OSSL_Functions.osSetPenColour(drawList, colour);
+        }
+
+        public string osDrawImage(string drawList, int width, int height, string imageUrl)
+        {
+            return m_OSSL_Functions.osDrawImage(drawList, width, height, imageUrl);
+        }
+        public void osSetStateEvents(int events)
+        {
+            m_OSSL_Functions.osSetStateEvents(events);
+        }
+    }
+}

+ 653 - 0
OpenSim/Region/ScriptEngine/XEngine/Script/ILSL_ScriptCommands.cs

@@ -0,0 +1,653 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using OpenSim.Region.Environment.Interfaces;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.Script
+{
+    public interface ILSL_ScriptCommands
+    {
+        // Interface used for loading and executing scripts
+
+        string State { get; set ; }
+
+        void state(string newState);
+
+        ICommander GetCommander(string name);
+
+        void llSay(int channelID, string text);
+        double llSin(double f);
+        double llCos(double f);
+        double llTan(double f);
+        double llAtan2(double x, double y);
+        double llSqrt(double f);
+        double llPow(double fbase, double fexponent);
+        LSL_Types.LSLInteger llAbs(int i);
+        double llFabs(double f);
+        double llFrand(double mag);
+        LSL_Types.LSLInteger llFloor(double f);
+        LSL_Types.LSLInteger llCeil(double f);
+        LSL_Types.LSLInteger llRound(double f);
+        double llVecMag(LSL_Types.Vector3 v);
+        LSL_Types.Vector3 llVecNorm(LSL_Types.Vector3 v);
+        double llVecDist(LSL_Types.Vector3 a, LSL_Types.Vector3 b);
+        LSL_Types.Vector3 llRot2Euler(LSL_Types.Quaternion r);
+        LSL_Types.Quaternion llEuler2Rot(LSL_Types.Vector3 v);
+        LSL_Types.Quaternion llAxes2Rot(LSL_Types.Vector3 fwd, LSL_Types.Vector3 left, LSL_Types.Vector3 up);
+        LSL_Types.Vector3 llRot2Fwd(LSL_Types.Quaternion r);
+        LSL_Types.Vector3 llRot2Left(LSL_Types.Quaternion r);
+        LSL_Types.Vector3 llRot2Up(LSL_Types.Quaternion r);
+        LSL_Types.Quaternion llRotBetween(LSL_Types.Vector3 start, LSL_Types.Vector3 end);
+        void llWhisper(int channelID, string text);
+        //void llSay(int channelID, string text);
+        void llShout(int channelID, string text);
+        void llRegionSay(int channelID, string text);
+        LSL_Types.LSLInteger llListen(int channelID, string name, string ID, string msg);
+        void llListenControl(int number, int active);
+        void llListenRemove(int number);
+        void llSensor(string name, string id, int type, double range, double arc);
+        void llSensorRepeat(string name, string id, int type, double range, double arc, double rate);
+        void llSensorRemove();
+        string llDetectedName(int number);
+        string llDetectedKey(int number);
+        string llDetectedOwner(int number);
+        LSL_Types.LSLInteger llDetectedType(int number);
+        LSL_Types.Vector3 llDetectedPos(int number);
+        LSL_Types.Vector3 llDetectedVel(int number);
+        LSL_Types.Vector3 llDetectedGrab(int number);
+        LSL_Types.Quaternion llDetectedRot(int number);
+        LSL_Types.LSLInteger llDetectedGroup(int number);
+        LSL_Types.LSLInteger llDetectedLinkNumber(int number);
+        void llDie();
+        double llGround(LSL_Types.Vector3 offset);
+        double llCloud(LSL_Types.Vector3 offset);
+        LSL_Types.Vector3 llWind(LSL_Types.Vector3 offset);
+        void llSetStatus(int status, int value);
+        LSL_Types.LSLInteger llGetStatus(int status);
+        void llSetScale(LSL_Types.Vector3 scale);
+        LSL_Types.Vector3 llGetScale();
+        void llSetColor(LSL_Types.Vector3 color, int face);
+        double llGetAlpha(int face);
+        void llSetAlpha(double alpha, int face);
+        LSL_Types.Vector3 llGetColor(int face);
+        void llSetTexture(string texture, int face);
+        void llScaleTexture(double u, double v, int face);
+        void llOffsetTexture(double u, double v, int face);
+        void llRotateTexture(double rotation, int face);
+        string llGetTexture(int face);
+        void llSetPos(LSL_Types.Vector3 pos);
+
+        //wiki: vector llGetPos()
+        LSL_Types.Vector3 llGetPos();
+        //wiki: vector llGetLocalPos()
+        LSL_Types.Vector3 llGetLocalPos();
+        //wiki: llSetRot(rotation rot)
+        void llSetRot(LSL_Types.Quaternion rot);
+        //wiki: rotation llGetRot()
+        LSL_Types.Quaternion llGetRot();
+        //wiki: rotation llGetLocalRot()
+        LSL_Types.Quaternion llGetLocalRot();
+        //wiki: llSetForce(vector force, integer local)
+        void llSetForce(LSL_Types.Vector3 force, int local);
+        //wiki: vector llGetForce()
+        LSL_Types.Vector3 llGetForce();
+        //wiki: integer llTarget(vector position, double range)
+        LSL_Types.LSLInteger llTarget(LSL_Types.Vector3 position, double range);
+        //wiki: llTargetRemove(integer number)
+        void llTargetRemove(int number);
+        //wiki: integer llRotTarget(rotation rot, double error)
+        LSL_Types.LSLInteger llRotTarget(LSL_Types.Quaternion rot, double error);
+        //wiki: integer llRotTargetRemove(integer number)
+        void llRotTargetRemove(int number);
+        //wiki: llMoveToTarget(vector target, double tau)
+        void llMoveToTarget(LSL_Types.Vector3 target, double tau);
+        //wiki: llStopMoveToTarget()
+        void llStopMoveToTarget();
+        //wiki: llApplyImpulse(vector force, integer local)
+        void llApplyImpulse(LSL_Types.Vector3 force, int local);
+        //wiki: llapplyRotationalImpulse(vector force, integer local)
+        void llApplyRotationalImpulse(LSL_Types.Vector3 force, int local);
+        //wiki: llSetTorque(vector torque, integer local)
+        void llSetTorque(LSL_Types.Vector3 torque, int local);
+        //wiki: vector llGetTorque()
+        LSL_Types.Vector3 llGetTorque();
+        //wiki: llSeForceAndTorque(vector force, vector torque, integer local)
+        void llSetForceAndTorque(LSL_Types.Vector3 force, LSL_Types.Vector3 torque, int local);
+        //wiki: vector llGetVel()
+        LSL_Types.Vector3 llGetVel();
+        //wiki: vector llGetAccel()
+        LSL_Types.Vector3 llGetAccel();
+        //wiki: vector llGetOmega()
+        LSL_Types.Vector3 llGetOmega();
+        //wiki: double llGetTimeOfDay()
+        double llGetTimeOfDay();
+        //wiki: double llGetWallclock()
+        double llGetWallclock();
+        //wiki: double llGetTime()
+        double llGetTime();
+        //wiki: llResetTime()
+        void llResetTime();
+        //wiki: double llGetAndResetTime()
+        double llGetAndResetTime();
+        //wiki (deprecated) llSound(string sound, double volume, integer queue, integer loop)
+        void llSound();
+        //wiki: llPlaySound(string sound, double volume)
+        void llPlaySound(string sound, double volume);
+        //wiki: llLoopSound(string sound, double volume)
+        void llLoopSound(string sound, double volume);
+        //wiki: llLoopSoundMaster(string sound, double volume)
+        void llLoopSoundMaster(string sound, double volume);
+        //wiki: llLoopSoundSlave(string sound, double volume)
+        void llLoopSoundSlave(string sound, double volume);
+        //wiki llPlaySoundSlave(string sound, double volume)
+        void llPlaySoundSlave(string sound, double volume);
+        //wiki: llTriggerSound(string sound, double volume)
+        void llTriggerSound(string sound, double volume);
+        //wiki: llStopSound()
+        void llStopSound();
+        //wiki: llPreloadSound(string sound)
+        void llPreloadSound(string sound);
+        //wiki: string llGetSubString(string src, integer start, integer end)
+        string llGetSubString(string src, int start, int end);
+        //wiki: string llDeleteSubString(string src, integer start, integer end)
+        string llDeleteSubString(string src, int start, int end);
+        //wiki string llInsertString(string dst, integer position, string src)
+        string llInsertString(string dst, int position, string src);
+        //wiki: string llToUpper(string source)
+        string llToUpper(string source);
+        //wiki: string llToLower(string source)
+        string llToLower(string source);
+        //wiki: integer llGiveMoney(key destination, integer amount)
+        LSL_Types.LSLInteger llGiveMoney(string destination, int amount);
+        //wiki: (deprecated)
+        void llMakeExplosion();
+        //wiki: (deprecated)
+        void llMakeFountain();
+        //wiki: (deprecated)
+        void llMakeSmoke();
+        //wiki: (deprecated)
+        void llMakeFire();
+        //wiki: llRezObject(string inventory, vector pos, vector rel, rotation rot, integer param)
+        void llRezObject(string inventory, LSL_Types.Vector3 pos, LSL_Types.Vector3 vel, LSL_Types.Quaternion rot, int param);
+        //wiki: llLookAt(vector target, double strength, double damping)
+        void llLookAt(LSL_Types.Vector3 target, double strength, double damping);
+        //wiki: llStopLookAt()
+        void llStopLookAt();
+        //wiki: llSetTimerEvent(double sec)
+        void llSetTimerEvent(double sec);
+        //wiki: llSleep(double sec)
+        void llSleep(double sec);
+        //wiki: double llGetMass()
+        double llGetMass();
+        //wiki: llCollisionFilter(string name, key id, integer accept)
+        void llCollisionFilter(string name, string id, int accept);
+        //wiki: llTakeControls(integer controls, integer accept, integer pass_on)
+        void llTakeControls(int controls, int accept, int pass_on);
+        //wiki: llReleaseControls()
+        void llReleaseControls();
+        //wiki: llAttachToAvatar(integer attachment)
+        void llAttachToAvatar(int attachment);
+        //wiki: llDetachFromAvatar()
+        void llDetachFromAvatar();
+        //wiki: (deprecated) llTakeCamera()
+        void llTakeCamera();
+        //wiki: (deprecated) llReleaseCamera()
+        void llReleaseCamera();
+        //wiki: key llGetOwner()
+        string llGetOwner();
+        //wiki: llInstantMessage(key user, string message)
+        void llInstantMessage(string user, string message);
+        //wiki: llEmail(string address, string subject, string message)
+        void llEmail(string address, string subject, string message);
+        //wiki: llGetNextEmail(string address, string subject)
+        void llGetNextEmail(string address, string subject);
+        //wiki:    key llGetKey()
+        string llGetKey();
+        //wiki: llSetBuoyancy(double buoyancy)
+        void llSetBuoyancy(double buoyancy);
+        //wiki: llSetHoverHeight(double height, integer water, double tau)
+        void llSetHoverHeight(double height, int water, double tau);
+        //wiki: llStopHover
+        void llStopHover();
+        //wiki: llMinEventDelay(double delay)
+        void llMinEventDelay(double delay);
+        //wiki: (deprecated) llSoundPreload()
+        void llSoundPreload();
+        //wiki: llRotLookAt(rotation target, double strength, double damping)
+        void llRotLookAt(LSL_Types.Quaternion target, double strength, double damping);
+        //wiki: integer llStringLength(string str)
+        LSL_Types.LSLInteger llStringLength(string str);
+        //wiki: llStartAnimation(string anim)
+        void llStartAnimation(string anim);
+        //wiki: llStopAnimation(string anim)
+        void llStopAnimation(string anim);
+        //wiki: (deprecated) llPointAt
+        void llPointAt();
+        //wiki: (deprecated) llStopPointAt
+        void llStopPointAt();
+        //wiki: llTargetOmega(vector axis, double spinrate, double gain)
+        void llTargetOmega(LSL_Types.Vector3 axis, double spinrate, double gain);
+        //wiki: integer llGetStartParameter()
+        LSL_Types.LSLInteger llGetStartParameter();
+        //wiki: llGodLikeRezObject(key inventory, vector pos)
+        void llGodLikeRezObject(string inventory, LSL_Types.Vector3 pos);
+        //wiki: llRequestPermissions(key agent, integer perm)
+        void llRequestPermissions(string agent, int perm);
+        //wiki: key llGetPermissionsKey()
+        string llGetPermissionsKey();
+        //wiki: integer llGetPermissions()
+        LSL_Types.LSLInteger llGetPermissions();
+        //wiki integer llGetLinkNumber()
+        LSL_Types.LSLInteger llGetLinkNumber();
+        //wiki: llSetLinkColor(integer linknumber, vector color, integer face)
+        void llSetLinkColor(int linknumber, LSL_Types.Vector3 color, int face);
+        //wiki: llCreateLink(key target, integer parent)
+        void llCreateLink(string target, int parent);
+        //wiki: llBreakLink(integer linknum)
+        void llBreakLink(int linknum);
+        //wiki: llBreakAllLinks()
+        void llBreakAllLinks();
+        //wiki: key llGetLinkKey(integer linknum)
+        string llGetLinkKey(int linknum);
+        //wiki: llGetLinkName(integer linknum)
+        string llGetLinkName(int linknum);
+        //wiki: integer llGetInventoryNumber(integer type)
+        LSL_Types.LSLInteger llGetInventoryNumber(int type);
+        //wiki: string llGetInventoryName(integer type, integer number)
+        string llGetInventoryName(int type, int number);
+        //wiki: llSetScriptState(string name, integer run)
+        void llSetScriptState(string name, int run);
+        //wiki: double llGetEnergy()
+        double llGetEnergy();
+        //wiki: llGiveInventory(key destination, string inventory)
+        void llGiveInventory(string destination, string inventory);
+        //wiki: llRemoveInventory(string item)
+        void llRemoveInventory(string item);
+        //wiki: llSetText(string text, vector color, double alpha)
+        void llSetText(string text, LSL_Types.Vector3 color, double alpha);
+        //wiki: double llWater(vector offset)
+        double llWater(LSL_Types.Vector3 offset);
+        //wiki: llPassTouches(integer pass)
+        void llPassTouches(int pass);
+        //wiki: key llRequestAgentData(key id, integer data)
+        string llRequestAgentData(string id, int data);
+        //wiki: key llRequestInventoryData(string name)
+        string llRequestInventoryData(string name);
+        //wiki: llSetDamage(double damage)
+        void llSetDamage(double damage);
+        //wiki: llTeleportAgentHome(key agent)
+        void llTeleportAgentHome(string agent);
+        //wiki: llModifyLand(integer action, integer brush)
+        void llModifyLand(int action, int brush);
+        //wiki: llCollisionSound(string impact_sound, double impact_volume)
+        void llCollisionSound(string impact_sound, double impact_volume);
+        //wiki: llCollisionSprite(string impact_sprite)
+        void llCollisionSprite(string impact_sprite);
+        //wiki: string llGetAnimation(key id)
+        string llGetAnimation(string id);
+        //wiki: llResetScript()
+        void llResetScript();
+        //wiki: llMessageLinked(integer linknum, integer num, string str, key id)
+        void llMessageLinked(int linknum, int num, string str, string id);
+        //wiki: llPushObject(key target, vector impulse, vector ang_impulse, integer local)
+        void llPushObject(string target, LSL_Types.Vector3 impulse, LSL_Types.Vector3 ang_impulse, int local);
+        //wiki: llPassCollisions(integer pass)
+        void llPassCollisions(int pass);
+        //wiki: string llGetScriptName()
+        string llGetScriptName();
+        //wiki: integer llGetNumberOfSides()
+        LSL_Types.LSLInteger llGetNumberOfSides();
+        //wiki: rotation llAxisAngle2Rot(vector axis, double angle)
+        LSL_Types.Quaternion llAxisAngle2Rot(LSL_Types.Vector3 axis, double angle);
+        //wiki: vector llRot2Axis(rotation rot)
+        LSL_Types.Vector3 llRot2Axis(LSL_Types.Quaternion rot);
+        //wiki: double llRot2Angle(rotation rot);
+        double llRot2Angle(LSL_Types.Quaternion rot);
+        //wiki: double llAcos(double val)
+        double llAcos(double val);
+        //wiki: double llAsin(double val)
+        double llAsin(double val);
+        //wiki: double llAngleBetween(rotation a, rotation b)
+        double llAngleBetween(LSL_Types.Quaternion a, LSL_Types.Quaternion b);
+        //wiki: string llGetInventoryKey(string name)
+        string llGetInventoryKey(string name);
+        //wiki: llAllowInventoryDrop(integer add)
+        void llAllowInventoryDrop(int add);
+        //wiki: vector llGetSunDirection()
+        LSL_Types.Vector3 llGetSunDirection();
+        //wiki: vector llGetTextureOffset(integer face)
+        LSL_Types.Vector3 llGetTextureOffset(int face);
+        //wiki: vector llGetTextureScale(integer side)
+        LSL_Types.Vector3 llGetTextureScale(int side);
+        //wiki: double llGetTextureRot(integer side)
+        double llGetTextureRot(int side);
+        //wiki: integer llSubStringIndex(string source, string pattern)
+        LSL_Types.LSLInteger llSubStringIndex(string source, string pattern);
+        //wiki: key llGetOwnerKey(key id)
+        string llGetOwnerKey(string id);
+        //wiki: vector llGetCenterOfMass()
+        LSL_Types.Vector3 llGetCenterOfMass();
+        //wiki: list llListSort(list src, integer stride, integer ascending)
+        LSL_Types.list llListSort(LSL_Types.list src, int stride, int ascending);
+        //integer llGetListLength(list src)
+        LSL_Types.LSLInteger llGetListLength(LSL_Types.list src);
+        //wiki: integer llList2Integer(list src, integer index)
+        LSL_Types.LSLInteger llList2Integer(LSL_Types.list src, int index);
+        //wiki: double llList2double(list src, integer index)
+        double llList2Float(LSL_Types.list src, int index);
+        //wiki: string llList2String(list src, integer index)
+        string llList2String(LSL_Types.list src, int index);
+        //wiki: key llList2Key(list src, integer index)
+        string llList2Key(LSL_Types.list src, int index);
+        //wiki: vector llList2Vector(list src, integer index)
+        LSL_Types.Vector3 llList2Vector(LSL_Types.list src, int index);
+        //wiki rotation llList2Rot(list src, integer index)
+        LSL_Types.Quaternion llList2Rot(LSL_Types.list src, int index);
+        //wiki: list llList2List(list src, integer start, integer end)
+        LSL_Types.list llList2List(LSL_Types.list src, int start, int end);
+        //wiki: llDeleteSubList(list src, integer start, integer end)
+        LSL_Types.list llDeleteSubList(LSL_Types.list src, int start, int end);
+        //wiki: integer llGetListEntryType(list src, integer index)
+        LSL_Types.LSLInteger llGetListEntryType(LSL_Types.list src, int index);
+        //wiki: string llList2CSV(list src)
+        string llList2CSV(LSL_Types.list src);
+        //wiki: list llCSV2List(string src)
+        LSL_Types.list llCSV2List(string src);
+        //wiki: list llListRandomize(list src, integer stride)
+        LSL_Types.list llListRandomize(LSL_Types.list src, int stride);
+        //wiki: list llList2ListStrided(list src, integer start, integer end, integer stride)
+        LSL_Types.list llList2ListStrided(LSL_Types.list src, int start, int end, int stride);
+        //wiki: vector llGetRegionCorner()
+        LSL_Types.Vector3 llGetRegionCorner();
+        //wiki: list llListInsertList(list dest, list src, integer start)
+        LSL_Types.list llListInsertList(LSL_Types.list dest, LSL_Types.list src, int start);
+        //wiki: integer llListFindList(list src, list test)
+        LSL_Types.LSLInteger llListFindList(LSL_Types.list src, LSL_Types.list test);
+        //wiki: string llGetObjectName()
+        string llGetObjectName();
+        //wiki: llSetObjectName(string name)
+        void llSetObjectName(string name);
+        //wiki: string llGetDate()
+        string llGetDate();
+        //wiki: integer llEdgeOfWorld(vector pos, vector dir)
+        LSL_Types.LSLInteger llEdgeOfWorld(LSL_Types.Vector3 pos, LSL_Types.Vector3 dir);
+        //wiki: integer llGetAgentInfo(key id)
+        LSL_Types.LSLInteger llGetAgentInfo(string id);
+        //wiki: llAdjustSoundVolume(double volume)
+        void llAdjustSoundVolume(double volume);
+        //wiki: llSetSoundQueueing(integer queue)
+        void llSetSoundQueueing(int queue);
+        //wiki: llSetSoundRadius(double radius)
+        void llSetSoundRadius(double radius);
+        //wiki: string llKey2Name(key id)
+        string llKey2Name(string id);
+        //wiki: llSetTextureAnim(integer mode, integer face, integer sizex, integer sizey, double start, double length, double rate)
+        void llSetTextureAnim(int mode, int face, int sizex, int sizey, double start, double length, double rate);
+        //wiki: llTriggerSoundLimited(string sound, double volume, vector top_north_east, vector bottom_south_west)
+        void llTriggerSoundLimited(string sound, double volume, LSL_Types.Vector3 top_north_east,
+                                   LSL_Types.Vector3 bottom_south_west);
+
+        //wiki: llEjectFromLand(key pest)
+        void llEjectFromLand(string pest);
+        LSL_Types.list llParseString2List(string str, LSL_Types.list separators, LSL_Types.list spacers);
+        //wiki: integer llOverMyLand(key id)
+        LSL_Types.LSLInteger llOverMyLand(string id);
+        //wiki: key llGetLandOwnerAt(vector pos)
+        string llGetLandOwnerAt(LSL_Types.Vector3 pos);
+        //wiki: key llGetNotecardLine(string name, integer line)
+        string llGetNotecardLine(string name, int line);
+        //wiki: vector llGetAgentSize(key id)
+        LSL_Types.Vector3 llGetAgentSize(string id);
+        //wiki: integer llSameGroup(key agent)
+        LSL_Types.LSLInteger llSameGroup(string agent);
+        //wiki: llUnSit(key id)
+        void llUnSit(string id);
+        //wiki: vector llGroundSlope(vector offset)
+        LSL_Types.Vector3 llGroundSlope(LSL_Types.Vector3 offset);
+        //wiki: vector llGroundNormal(vector offset)
+        LSL_Types.Vector3 llGroundNormal(LSL_Types.Vector3 offset);
+        //wiki: vector llGroundContour(vector offset)
+        LSL_Types.Vector3 llGroundContour(LSL_Types.Vector3 offset);
+        //wiki: integer llGetAttached()
+        LSL_Types.LSLInteger llGetAttached();
+        //wiki: integer llGetFreeMemory()
+        LSL_Types.LSLInteger llGetFreeMemory();
+        //wiki: string llGetRegionName()
+        string llGetRegionName();
+        //wiki: double llGetRegionTimeDilation()
+        double llGetRegionTimeDilation();
+        //wiki: double llGetRegionFPS()
+        double llGetRegionFPS();
+        //wiki: llParticleSystem(List<Object> rules
+        void llParticleSystem(LSL_Types.list rules);
+        //wiki: llGroundRepel(double height, integer water, double tau)
+        void llGroundRepel(double height, int water, double tau);
+        //wiki: llGiveInventoryList(string destination, string category, LSL_Types.list inventory)
+        void llGiveInventoryList(string destination, string category, LSL_Types.list inventory);
+        //wiki: llSetVehicleType(integer type)
+        void llSetVehicleType(int type);
+        //wiki: llSetVehicledoubleParam(integer param, double value)
+        void llSetVehicledoubleParam(int param, double value);
+        // wiki: llSetVehicleFloatParam(integer param, float value)
+        void llSetVehicleFloatParam(int param, float value);
+        //wiki: llSetVehicleVectorParam(integer param, vector vec)
+        void llSetVehicleVectorParam(int param, LSL_Types.Vector3 vec);
+        //wiki: llSetVehicleRotationParam(integer param, rotation rot)
+        void llSetVehicleRotationParam(int param, LSL_Types.Quaternion rot);
+        //wiki: llSetVehicleFlags(integer flags)
+        void llSetVehicleFlags(int flags);
+        //wiki: llRemoveVehicleFlags(integer flags)
+        void llRemoveVehicleFlags(int flags);
+        //wiki: llSitTarget(vector offset, rotation rot)
+        void llSitTarget(LSL_Types.Vector3 offset, LSL_Types.Quaternion rot);
+        //wiki key llAvatarOnSitTarget()
+        string llAvatarOnSitTarget();
+        //wiki: llAddToLandPassList(key avatar, double hours)
+        void llAddToLandPassList(string avatar, double hours);
+        //wiki: llSetTouchText(string text)
+        void llSetTouchText(string text);
+        //wiki: llSetSitText(string text)
+        void llSetSitText(string text);
+        //wiki: llSetCameraEyeOffset(vector offset)
+        void llSetCameraEyeOffset(LSL_Types.Vector3 offset);
+        //wiki: llSeteCameraAtOffset(vector offset)
+        void llSetCameraAtOffset(LSL_Types.Vector3 offset);
+        //
+        string llDumpList2String(LSL_Types.list src, string seperator);
+        //wiki: integer llScriptDanger(vector pos)
+        LSL_Types.LSLInteger llScriptDanger(LSL_Types.Vector3 pos);
+        //wiki: llDialog(key avatar, string message, list buttons, integer chat_channel)
+        void llDialog(string avatar, string message, LSL_Types.list buttons, int chat_channel);
+        //wiki: llVolumeDetect(integer detect)
+        void llVolumeDetect(int detect);
+        //wiki: llResetOtherScript(string name)
+        void llResetOtherScript(string name);
+        //wiki: integer llGetScriptState(string name)
+        LSL_Types.LSLInteger llGetScriptState(string name);
+        //wiki: (deprecated)
+        void llRemoteLoadScript();
+        //wiki: llSetRemoteScriptAccessPin(integer pin)
+        void llSetRemoteScriptAccessPin(int pin);
+        //wiki: llRemoteLoadScriptPin(key target, string name, integer pin, integer running, integer start_param)
+        void llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param);
+        //wiki: llOpenRemoteDataChannel()
+        void llOpenRemoteDataChannel();
+        //wiki: key llSendRemoteData(key channel, string dest, integer idata, string sdata)
+        string llSendRemoteData(string channel, string dest, int idata, string sdata);
+        //wiki: llRemoteDataReply(key channel, key message_id, string sdata, integer idata)
+        void llRemoteDataReply(string channel, string message_id, string sdata, int idata);
+        //wiki: llCloseRemoteDataChannel(key channel)
+        void llCloseRemoteDataChannel(string channel);
+        //wiki: string llMD5String(string src, integer nonce)
+        string llMD5String(string src, int nonce);
+        //wiki: llSetPrimitiveParams(list rules)
+        void llSetPrimitiveParams(LSL_Types.list rules);
+        //wiki: llSetLinkPrimitiveParams(integer linknumber, list rules)
+        void llSetLinkPrimitiveParams(int linknumber, LSL_Types.list rules);
+        //wiki: string llStringToBase64(string str)
+        string llStringToBase64(string str);
+        //wiki: string llBase64ToString(string str)
+        string llBase64ToString(string str);
+        //wiki: (deprecated)
+        void llXorBase64Strings();
+        //wiki: llRemoteDataSetRegion()
+        void llRemoteDataSetRegion();
+        //wiki: double llLog10(double val)
+        double llLog10(double val);
+        //wiki: double llLog(double val)
+        double llLog(double val);
+        //wiki: list llGetAnimationList(key id)
+        LSL_Types.list llGetAnimationList(string id);
+        //wiki: llSetParcelMusicURL(string url)
+        void llSetParcelMusicURL(string url);
+        //wiki: vector llGetRootPosition()
+        LSL_Types.Vector3 llGetRootPosition();
+        //wiki: rotation llGetRootRotation()
+        LSL_Types.Quaternion llGetRootRotation();
+        //wiki: string llGetObjectDesc()
+        string llGetObjectDesc();
+        //wiki: llSetObjectDesc(string desc)
+        void llSetObjectDesc(string desc);
+        //wiki: key llGetCreator()
+        string llGetCreator();
+        //wiki: string llGetTimestamp()
+        string llGetTimestamp();
+        //wiki: llSetLinkAlpha(integer linknumber, double alpha, integer face)
+        void llSetLinkAlpha(int linknumber, double alpha, int face);
+        //wiki: integer llGetNumberOfPrims()
+        LSL_Types.LSLInteger llGetNumberOfPrims();
+        //wiki: key llGetNumberOfNotecardLines(string name)
+        string llGetNumberOfNotecardLines(string name);
+        //wiki: list llGetBoundingBox(key object)
+        LSL_Types.list llGetBoundingBox(string obj);
+        //wiki: vector llGetGeometricCenter()
+        LSL_Types.Vector3 llGetGeometricCenter();
+        //wiki: list llGetPrimitiveParams(list rules)
+        LSL_Types.list llGetPrimitiveParams(LSL_Types.list rules);
+        //wiki: string llIntegerToBase64(integer number)
+        string llIntegerToBase64(int number);
+        //wiki integer llBase64ToInteger(string str)
+        LSL_Types.LSLInteger llBase64ToInteger(string str);
+        //wiki: double llGetGMTclock()
+        double llGetGMTclock();
+        //wiki: string llGetSimulatorHostname()
+        string llGetSimulatorHostname();
+        //llSetLocalRot(rotation rot)
+        void llSetLocalRot(LSL_Types.Quaternion rot);
+        //wiki: list llParseStringKeepNulls(string src, list separators, list spacers)
+        LSL_Types.list llParseStringKeepNulls(string src, LSL_Types.list seperators, LSL_Types.list spacers);
+        //wiki: llRezAtRoot(string inventory, vector position, vector velocity, rotation rot, integer param)
+        void llRezAtRoot(string inventory, LSL_Types.Vector3 position, LSL_Types.Vector3 velocity,
+                         LSL_Types.Quaternion rot, int param);
+
+        //wiki: integer llGetObjectPermMask(integer mask)
+        LSL_Types.LSLInteger llGetObjectPermMask(int mask);
+        //wiki: llSetObjectPermMask(integer mask, integer value)
+        void llSetObjectPermMask(int mask, int value);
+        //wiki integer llGetInventoryPermMask(string item, integer mask)
+        LSL_Types.LSLInteger llGetInventoryPermMask(string item, int mask);
+        //wiki: llSetInventoryPermMask(string item, integer mask, integer value)
+        void llSetInventoryPermMask(string item, int mask, int value);
+        //wiki: key llGetInventoryCreator(string item)
+        string llGetInventoryCreator(string item);
+        //wiki: llOwnerSay(string msg)
+        void llOwnerSay(string msg);
+        //wiki: key llRequestSimulatorData(string simulator, integer data)
+        string llRequestSimulatorData(string simulator, int data);
+        //wiki: llForceMouselook(integer mouselook)
+        void llForceMouselook(int mouselook);
+        //wiki: double llGetObjectMass(key id)
+        double llGetObjectMass(string id);
+        LSL_Types.list llListReplaceList(LSL_Types.list dest, LSL_Types.list src, int start, int end);
+        //wiki: llLoadURL(key avatar_id, string message, string url)
+        void llLoadURL(string avatar_id, string message, string url);
+        //wiki: llParcelMediaCommandList(list commandList)
+        void llParcelMediaCommandList(LSL_Types.list commandList);
+        void llParcelMediaQuery();
+        //wiki integer llModPow(integer a, integer b, integer c)
+        LSL_Types.LSLInteger llModPow(int a, int b, int c);
+        //wiki: integer llGetInventoryType(string name)
+        LSL_Types.LSLInteger llGetInventoryType(string name);
+        //wiki: llSetPayPrice(integer price, list quick_pay_buttons)
+        void llSetPayPrice(int price, LSL_Types.list quick_pay_buttons);
+        //wiki: vector llGetCameraPos()
+        LSL_Types.Vector3 llGetCameraPos();
+        //wiki rotation llGetCameraRot()
+        LSL_Types.Quaternion llGetCameraRot();
+        //wiki: (deprecated)
+        void llSetPrimURL();
+        //wiki: (deprecated)
+        void llRefreshPrimURL();
+        //wiki: string llEscapeURL(string url)
+        string llEscapeURL(string url);
+        //wiki: string llUnescapeURL(string url)
+        string llUnescapeURL(string url);
+        //wiki: llMapDestination(string simname, vector pos, vector look_at)
+        void llMapDestination(string simname, LSL_Types.Vector3 pos, LSL_Types.Vector3 look_at);
+        //wiki: llAddToLandBanList(key avatar, double hours)
+        void llAddToLandBanList(string avatar, double hours);
+        //wiki: llRemoveFromLandPassList(key avatar)
+        void llRemoveFromLandPassList(string avatar);
+        //wiki: llRemoveFromLandBanList(key avatar)
+        void llRemoveFromLandBanList(string avatar);
+        //wiki: llSetCameraParams(list rules)
+        void llSetCameraParams(LSL_Types.list rules);
+        //wiki: llClearCameraParams()
+        void llClearCameraParams();
+        //wiki: double llListStatistics(integer operation, list src)
+        double llListStatistics(int operation, LSL_Types.list src);
+        //wiki: integer llGetUnixTime()
+        LSL_Types.LSLInteger llGetUnixTime();
+        //wiki: integer llGetParcelFlags(vector pos)
+        LSL_Types.LSLInteger llGetParcelFlags(LSL_Types.Vector3 pos);
+        //wiki: integer llGetRegionFlags()
+        LSL_Types.LSLInteger llGetRegionFlags();
+        //wiki: string llXorBase64StringsCorrect(string str1, string str2)
+        string llXorBase64StringsCorrect(string str1, string str2);
+        string llHTTPRequest(string url, LSL_Types.list parameters, string body);
+        //wiki: llResetLandBanList()
+        void llResetLandBanList();
+        //wiki: llResetLandPassList()
+        void llResetLandPassList();
+        //wiki: integer llGetParcelPrimCount(vector pos, integer category, integer sim_wide)
+        LSL_Types.LSLInteger llGetParcelPrimCount(LSL_Types.Vector3 pos, int category, int sim_wide);
+        //wiki: list llGetParcelPrimOwners(vector pos)
+        LSL_Types.list llGetParcelPrimOwners(LSL_Types.Vector3 pos);
+        //wiki: integer llGetObjectPrimCount(key object_id)
+        LSL_Types.LSLInteger llGetObjectPrimCount(string object_id);
+        //wiki: integer llGetParcelMaxPrims(vector pos, integer sim_wide)
+        LSL_Types.LSLInteger llGetParcelMaxPrims(LSL_Types.Vector3 pos, int sim_wide);
+        //wiki: llGetParcelDetails(vector pos, list params)
+        LSL_Types.list llGetParcelDetails(LSL_Types.Vector3 pos, LSL_Types.list param);
+        //wiki: llSetLinkTexture(integer linknumber, string texture, integer face)
+        void llSetLinkTexture(int linknumber, string texture, int face);
+        //wiki: string llStringTrim(string src, int type)
+        string llStringTrim(string src, int type);
+        //wiki: LSL_Types.list llGetObjectDetails(string id, LSL_Types.list args)
+        LSL_Types.list llGetObjectDetails(string id, LSL_Types.list args);
+    }
+}

+ 68 - 0
OpenSim/Region/ScriptEngine/XEngine/Script/IOSSL_ScriptCommands.cs

@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+namespace OpenSim.Region.ScriptEngine.XEngine.Script
+{
+    public interface IOSSL_ScriptCommands
+    {
+        //OpenSim functions
+        string osSetDynamicTextureURL(string dynamicID, string contentType, string url, string extraParams, int timer);
+        string osSetDynamicTextureURLBlend(string dynamicID, string contentType, string url, string extraParams,
+                                           int timer, int alpha);
+        string osSetDynamicTextureData(string dynamicID, string contentType, string data, string extraParams, int timer);
+        string osSetDynamicTextureDataBlend(string dynamicID, string contentType, string data, string extraParams,
+                                            int timer, int alpha);
+        double osTerrainGetHeight(int x, int y);
+        int osTerrainSetHeight(int x, int y, double val);
+        int osRegionRestart(double seconds);
+        void osRegionNotice(string msg);
+        bool osConsoleCommand(string Command);
+        void osSetParcelMediaURL(string url);
+        void osSetPrimFloatOnWater(int floatYN);
+
+        // Animation commands
+        void osAvatarPlayAnimation(string avatar, string animation);
+        void osAvatarStopAnimation(string avatar, string animation);
+
+        //texture draw functions
+        string osMovePen(string drawList, int x, int y);
+        string osDrawLine(string drawList, int startX, int startY, int endX, int endY);
+        string osDrawLine(string drawList, int endX, int endY);
+        string osDrawText(string drawList, string text);
+        string osDrawEllipse(string drawList, int width, int height);
+        string osDrawRectangle(string drawList, int width, int height);
+        string osDrawFilledRectangle(string drawList, int width, int height);
+        string osSetFontSize(string drawList, int fontSize);
+        string osSetPenSize(string drawList, int penSize);
+        string osSetPenColour(string drawList, string colour);
+        string osDrawImage(string drawList, int width, int height, string imageUrl);
+        void osSetStateEvents(int events);
+
+        double osList2Double(LSL_Types.list src, int index);
+        void osSetRegionWaterHeight(double height);
+    }
+}

+ 46 - 0
OpenSim/Region/ScriptEngine/XEngine/Script/IScript.cs

@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System.Reflection;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using OpenSim.Region.Environment.Interfaces;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.Script
+{
+    public interface IScript
+    {
+        Type Start(ILSL_ScriptCommands lsl, IOSSL_ScriptCommands ossl);
+
+        Dictionary<string, object> GetVars();
+        void SetVars(Dictionary<string, object> vars);
+        void ResetVars();
+
+        string State { get; set; }
+    }
+}

+ 1411 - 0
OpenSim/Region/ScriptEngine/XEngine/Script/LSL_Types.cs

@@ -0,0 +1,1411 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the OpenSim Project nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections;
+using System.Text.RegularExpressions;
+
+namespace OpenSim.Region.ScriptEngine.XEngine.Script
+{
+    [Serializable]
+    public partial class LSL_Types
+    {
+        // Types are kept is separate .dll to avoid having to add whatever .dll it is in it to script AppDomain
+
+        [Serializable]
+        public struct Vector3
+        {
+            public double x;
+            public double y;
+            public double z;
+
+            #region Constructors
+
+            public Vector3(Vector3 vector)
+            {
+                x = (float)vector.x;
+                y = (float)vector.y;
+                z = (float)vector.z;
+            }
+
+            public Vector3(double X, double Y, double Z)
+            {
+                x = X;
+                y = Y;
+                z = Z;
+            }
+
+            public Vector3(string str)
+            {
+                str = str.Replace('<', ' ');
+                str = str.Replace('>', ' ');
+                string[] tmps = str.Split(new Char[] { ',', '<', '>' });
+                if (tmps.Length < 3)
+                {
+                    x=y=z=0;
+                    return;
+                }
+                bool res;
+                res = Double.TryParse(tmps[0], out x);
+                res = res & Double.TryParse(tmps[1], out y);
+                res = res & Double.TryParse(tmps[2], out z);
+            }
+
+            #endregion
+
+            #region Overriders
+
+            public override string ToString()
+            {
+                string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", x, y, z);
+                return s;
+            }
+
+            public static explicit operator LSLString(Vector3 vec)
+            {
+                string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z);
+                return new LSLString(s);
+            }
+
+            public static explicit operator string(Vector3 vec)
+            {
+                string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z);
+                return s;
+            }
+
+            public static explicit operator Vector3(string s)
+            {
+                return new Vector3(s);
+            }
+
+            public static bool operator ==(Vector3 lhs, Vector3 rhs)
+            {
+                return (lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z);
+            }
+
+            public static bool operator !=(Vector3 lhs, Vector3 rhs)
+            {
+                return !(lhs == rhs);
+            }
+
+            public override int GetHashCode()
+            {
+                return (x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode());
+            }
+
+            public override bool Equals(object o)
+            {
+                if (!(o is Vector3)) return false;
+
+                Vector3 vector = (Vector3)o;
+
+                return (x == vector.x && x == vector.x && z == vector.z);
+            }
+
+            #endregion
+
+            #region Vector & Vector Math
+
+            // Vector-Vector Math
+            public static Vector3 operator +(Vector3 lhs, Vector3 rhs)
+            {
+                return new Vector3(lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z);
+            }
+
+            public static Vector3 operator -(Vector3 lhs, Vector3 rhs)
+            {
+                return new Vector3(lhs.x - rhs.x, lhs.y - rhs.y, lhs.z - rhs.z);
+            }
+
+            public static Vector3 operator *(Vector3 lhs, Vector3 rhs)
+            {
+                return new Vector3(lhs.x * rhs.x, lhs.y * rhs.y, lhs.z * rhs.z);
+            }
+
+            public static Vector3 operator %(Vector3 v1, Vector3 v2)
+            {
+                //Cross product
+                Vector3 tv;
+                tv.x = (v1.y * v2.z) - (v1.z * v2.y);
+                tv.y = (v1.z * v2.x) - (v1.x * v2.z);
+                tv.z = (v1.x * v2.y) - (v1.y * v2.x);
+                return tv;
+            }
+
+            #endregion
+
+            #region Vector & Float Math
+
+            // Vector-Float and Float-Vector Math
+            public static Vector3 operator *(Vector3 vec, float val)
+            {
+                return new Vector3(vec.x * val, vec.y * val, vec.z * val);
+            }
+
+            public static Vector3 operator *(float val, Vector3 vec)
+            {
+                return new Vector3(vec.x * val, vec.y * val, vec.z * val);
+            }
+
+            public static Vector3 operator /(Vector3 v, float f)
+            {
+                v.x = v.x / f;
+                v.y = v.y / f;
+                v.z = v.z / f;
+                return v;
+            }
+
+            #endregion
+
+            #region Vector & Double Math
+
+            public static Vector3 operator *(Vector3 vec, double val)
+            {
+                return new Vector3(vec.x * val, vec.y * val, vec.z * val);
+            }
+
+            public static Vector3 operator *(double val, Vector3 vec)
+            {
+                return new Vector3(vec.x * val, vec.y * val, vec.z * val);
+            }
+
+            public static Vector3 operator /(Vector3 v, double f)
+            {
+                v.x = v.x / f;
+                v.y = v.y / f;
+                v.z = v.z / f;
+                return v;
+            }
+
+            #endregion
+
+            #region Vector & Rotation Math
+
+            // Vector-Rotation Math
+            public static Vector3 operator *(Vector3 v, Quaternion r)
+            {
+                Quaternion vq = new Quaternion(v.x, v.y, v.z, 0);
+                Quaternion nq = new Quaternion(-r.x, -r.y, -r.z, r.s);
+
+                // adapted for operator * computing "b * a"
+                Quaternion result = nq * (vq * r);
+
+                return new Vector3(result.x, result.y, result.z);
+            }
+
+            public static Vector3 operator /(Vector3 v, Quaternion r)
+            {
+                r.s = -r.s;
+                return v * r;
+            }
+
+            #endregion
+
+            #region Static Helper Functions
+
+            public static double Dot(Vector3 v1, Vector3 v2)
+            {
+                return (v1.x * v2.x) + (v1.y * v2.y) + (v1.z * v2.z);
+            }
+
+            public static Vector3 Cross(Vector3 v1, Vector3 v2)
+            {
+                return new Vector3
+                    (
+                    v1.y * v2.z - v1.z * v2.y,
+                    v1.z * v2.x - v1.x * v2.z,
+                    v1.x * v2.y - v1.y * v2.x
+                    );
+            }
+
+            public static double Mag(Vector3 v)
+            {
+                return Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
+            }
+
+            public static Vector3 Norm(Vector3 vector)
+            {
+                double mag = Mag(vector);
+                return new Vector3(vector.x / mag, vector.y / mag, vector.z / mag);
+            }
+
+            #endregion
+        }
+
+        [Serializable]
+        public struct Quaternion
+        {
+            public double x;
+            public double y;
+            public double z;
+            public double s;
+
+            #region Constructors
+
+            public Quaternion(Quaternion Quat)
+            {
+                x = (float)Quat.x;
+                y = (float)Quat.y;
+                z = (float)Quat.z;
+                s = (float)Quat.s;
+                if (x == 0 && y == 0 && z == 0 && s == 0)
+                    s = 1;
+            }
+
+            public Quaternion(double X, double Y, double Z, double S)
+            {
+                x = X;
+                y = Y;
+                z = Z;
+                s = S;
+                if (x == 0 && y == 0 && z == 0 && s == 0)
+                    s = 1;
+            }
+
+            public Quaternion(string str)
+            {
+                str = str.Replace('<', ' ');
+                str = str.Replace('>', ' ');
+                string[] tmps = str.Split(new Char[] { ',', '<', '>' });
+                if (tmps.Length < 4)
+                {
+                    x=y=z=s=0;
+                    return;
+                }
+                bool res;
+                res = Double.TryParse(tmps[0], out x);
+                res = res & Double.TryParse(tmps[1], out y);
+                res = res & Double.TryParse(tmps[2], out z);
+                res = res & Double.TryParse(tmps[3], out s);
+                if (x == 0 && y == 0 && z == 0 && s == 0)
+                    s = 1;
+            }
+
+            #endregion
+
+            #region Overriders
+
+            public override int GetHashCode()
+            {
+                return (x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ s.GetHashCode());
+            }
+
+            public override bool Equals(object o)
+            {
+                if (!(o is Quaternion)) return false;
+
+                Quaternion quaternion = (Quaternion)o;
+
+                return x == quaternion.x && y == quaternion.y && z == quaternion.z && s == quaternion.s;
+            }
+
+            public override string ToString()
+            {
+                string st=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000},{3:0.000000}>", x, y, z, s);
+                return st;
+            }
+
+            public static explicit operator string(Quaternion r)
+            {
+                string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000},{3:0.000000}>", r.x, r.y, r.z, r.s);
+                return s;
+            }
+
+            public static explicit operator LSLString(Quaternion r)
+            {
+                string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000},{3:0.000000}>", r.x, r.y, r.z, r.s);
+                return new LSLString(s);
+            }
+
+            public static explicit operator Quaternion(string s)
+            {
+                return new Quaternion(s);
+            }
+
+            public static bool operator ==(Quaternion lhs, Quaternion rhs)
+            {
+                // Return true if the fields match:
+                return lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z && lhs.s == rhs.s;
+            }
+
+            public static bool operator !=(Quaternion lhs, Quaternion rhs)
+            {
+                return !(lhs == rhs);
+            }
+
+            #endregion
+
+            public static Quaternion operator +(Quaternion a, Quaternion b)
+            {
+                return new Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.s + b.s);
+            }
+
+            public static Quaternion operator /(Quaternion a, Quaternion b)
+            {
+                b.s = -b.s;
+                return a * b;
+            }
+
+            public static Quaternion operator -(Quaternion a, Quaternion b)
+            {
+                return new Quaternion(a.x - b.x, a.y - b.y, a.z - b.z, a.s - b.s);
+            }
+
+            // using the equations below, we need to do "b * a" to be compatible with LSL
+            public static Quaternion operator *(Quaternion b, Quaternion a)
+            {
+                Quaternion c;
+                c.x = a.s * b.x + a.x * b.s + a.y * b.z - a.z * b.y;
+                c.y = a.s * b.y + a.y * b.s + a.z * b.x - a.x * b.z;
+                c.z = a.s * b.z + a.z * b.s + a.x * b.y - a.y * b.x;
+                c.s = a.s * b.s - a.x * b.x - a.y * b.y - a.z * b.z;
+                return c;
+            }
+        }
+
+        [Serializable]
+        public class list
+        {
+            private object[] m_data;
+
+            public list(params object[] args)
+            {
+                m_data = new object[args.Length];
+                m_data = args;
+            }
+
+            public int Length
+            {
+                get {
+                    if (m_data == null)
+                        m_data=new Object[0];
+                    return m_data.Length;
+                }
+            }
+
+            public object[] Data
+            {
+                get {
+                    if (m_data == null)
+                        m_data=new Object[0];
+                    return m_data;
+                }
+            }
+
+            public static list operator +(list a, list b)
+            {
+                object[] tmp;
+                tmp = new object[a.Length + b.Length];
+                a.Data.CopyTo(tmp, 0);
+                b.Data.CopyTo(tmp, a.Length);
+                return new list(tmp);
+            }
+
+            public void Add(object o)
+            {
+                object[] tmp;
+                tmp = new object[m_data.Length + 1];
+                m_data.CopyTo(tmp, 0);
+                tmp[m_data.Length] = o;
+                m_data = tmp;
+            }
+
+            public bool Contains(object o)
+            {
+                bool ret = false;
+                foreach (object i in Data)
+                {
+                    if (i == o)
+                    {
+                        ret = true;
+                        break;
+                    }
+                }
+                return ret;
+            }
+
+            public list DeleteSublist(int start, int end)
+            {
+                // Not an easy one
+                // If start <= end, remove that part
+                // if either is negative, count from the end of the array
+                // if the resulting start > end, remove all BUT that part
+
+                Object[] ret;
+
+                if (start < 0)
+                    start=m_data.Length-start;
+
+                if (start < 0)
+                    start=0;
+
+                if (end < 0)
+                    end=m_data.Length-end;
+                if (end < 0)
+                    end=0;
+
+                if (start > end)
+                {
+                    if (end >= m_data.Length)
+                        return new list(new Object[0]);
+
+                    if (start >= m_data.Length)
+                        start=m_data.Length-1;
+
+                    return GetSublist(end, start);
+                }
+
+                // start >= 0 && end >= 0 here
+                if (start >= m_data.Length)
+                {
+                    ret=new Object[m_data.Length];
+                    Array.Copy(m_data, 0, ret, 0, m_data.Length);
+
+                    return new list(ret);
+                }
+
+                if (end >= m_data.Length)
+                    end=m_data.Length-1;
+
+                // now, this makes the math easier
+                int remove=end+1-start;
+
+                ret=new Object[m_data.Length-remove];
+                if (ret.Length == 0)
+                    return new list(ret);
+
+                int src;
+                int dest=0;
+
+                for (src = 0; src < m_data.Length; src++)
+                {
+                    if (src < start || src > end)
+                        ret[dest++]=m_data[src];
+                }
+
+                return new list(ret);
+            }
+
+            public list GetSublist(int start, int end)
+            {
+
+                object[] ret;
+
+                // Take care of neg start or end's
+                // NOTE that either index may still be negative after
+                // adding the length, so we must take additional
+                // measures to protect against this. Note also that
+                // after normalisation the negative indices are no
+                // longer relative to the end of the list.
+
+                if (start < 0)
+                {
+                    start = m_data.Length + start;
+                }
+
+                if (end < 0)
+                {
+                    end = m_data.Length + end;
+                }
+
+                // The conventional case is start <= end
+                // NOTE that the case of an empty list is
+                // dealt with by the initial test. Start
+                // less than end is taken to be the most
+                // common case.
+
+                if (start <= end)
+                {
+
+                    // Start sublist beyond length
+                    // Also deals with start AND end still negative
+                    if (start >= m_data.Length || end < 0)
+                    {
+                        return new list();
+                    }
+
+                    // Sublist extends beyond the end of the supplied list
+                    if (end >= m_data.Length)
+                    {
+                        end = m_data.Length - 1;
+                    }
+
+                    // Sublist still starts before the beginning of the list
+                    if (start < 0)
+                    {
+                        start = 0;
+                    }
+
+                    ret = new object[end - start + 1];
+
+                    Array.Copy(m_data, start, ret, 0, end - start + 1);
+
+                    return new list(ret);
+
+                }
+
+                // Deal with the segmented case: 0->end + start->EOL
+
+                else
+                {
+
+                    list result = null;
+
+                    // If end is negative, then prefix list is empty
+                    if (end < 0)
+                    {
+                        result = new list();
+                        // If start is still negative, then the whole of
+                        // the existing list is returned. This case is
+                        // only admitted if end is also still negative.
+                        if (start < 0)
+                        {
+                            return this;
+                        }
+
+                    }
+                    else
+                    {
+                        result = GetSublist(0,end);
+                    }
+
+                    // If start is outside of list, then just return
+                    // the prefix, whatever it is.
+                    if (start >= m_data.Length)
+                    {
+                        return result;
+                    }
+
+                    return result + GetSublist(start, Data.Length);
+
+                }
+            }
+
+            public list Sort(int stride, int ascending)
+            {
+                if (Data.Length == 0)
+                    return new list(); // Don't even bother
+
+                string[] keys;
+
+                if (stride == 1) // The simple case
+                {
+                    Object[] ret=new Object[Data.Length];
+
+                    Array.Copy(Data, 0, ret, 0, Data.Length);
+
+                    keys=new string[Data.Length];
+
+                    for (int k = 0; k < Data.Length; k++)
+                        keys[k] = Data[k].ToString();
+
+                    Array.Sort(keys, ret);
+
+                    if (ascending == 0)
+                        Array.Reverse(ret);
+                    return new list(ret);
+                }
+
+                int src=0;
+
+                int len=(Data.Length+stride-1)/stride;
+
+                keys=new string[len];
+                Object[][] vals=new Object[len][];
+
+                int i;
+
+                while (src < Data.Length)
+                {
+                    Object[] o=new Object[stride];
+
+                    for (i = 0; i < stride; i++)
+                    {
+                        if (src < Data.Length)
+                            o[i]=Data[src++];
+                        else
+                        {
+                            o[i]=new Object();
+                            src++;
+                        }
+                    }
+
+                    int idx=src/stride-1;
+                    keys[idx]=o[0].ToString();
+                    vals[idx]=o;
+                }
+
+                Array.Sort(keys, vals);
+                if (ascending == 0)
+                {
+                    Array.Reverse(vals);
+                }
+
+                Object[] sorted=new Object[stride*vals.Length];
+
+                for (i = 0; i < vals.Length; i++)
+                    for (int j = 0; j < stride; j++)
+                        sorted[i*stride+j] = vals[i][j];
+
+                return new list(sorted);
+            }
+
+            #region CSV Methods
+
+            public static list FromCSV(string csv)
+            {
+                return new list(csv.Split(','));
+            }
+
+            public string ToCSV()
+            {
+                string ret = "";
+                foreach (object o in this.Data)
+                {
+                    if (ret == "")
+                    {
+                        ret = o.ToString();
+                    }
+                    else
+                    {
+                        ret = ret + ", " + o.ToString();
+                    }
+                }
+                return ret;
+            }
+
+            private string ToSoup()
+            {
+                string output;
+                output = String.Empty;
+                if (m_data.Length == 0)
+                {
+                    return String.Empty;
+                }
+                foreach (object o in m_data)
+                {
+                    output = output + o.ToString();
+                }
+                return output;
+            }
+
+            public static explicit operator String(list l)
+            {
+                return l.ToSoup();
+            }
+
+            public static explicit operator LSLString(list l)
+            {
+                return new LSLString(l.ToSoup());
+            }
+
+            public override string ToString()
+            {
+                return ToSoup();
+            }
+
+            #endregion
+
+            #region Statistic Methods
+
+            public double Min()
+            {
+                double minimum = double.PositiveInfinity;
+                double entry;
+                for (int i = 0; i < Data.Length; i++)
+                {
+                    if (double.TryParse(Data[i].ToString(), out entry))
+                    {
+                        if (entry < minimum) minimum = entry;
+                    }
+                }
+                return minimum;
+            }
+
+            public double Max()
+            {
+                double maximum = double.NegativeInfinity;
+                double entry;
+                for (int i = 0; i < Data.Length; i++)
+                {
+                    if (double.TryParse(Data[i].ToString(), out entry))
+                    {
+                        if (entry > maximum) maximum = entry;
+                    }
+                }
+                return maximum;
+            }
+
+            public double Range()
+            {
+                return (this.Max() / this.Min());
+            }
+
+            public int NumericLength()
+            {
+                int count = 0;
+                double entry;
+                for (int i = 0; i < Data.Length; i++)
+                {
+                    if (double.TryParse(Data[i].ToString(), out entry))
+                    {
+                        count++;
+                    }
+                }
+                return count;
+            }
+
+            public static list ToDoubleList(list src)
+            {
+                list ret = new list();
+                double entry;
+                for (int i = 0; i < src.Data.Length - 1; i++)
+                {
+                    if (double.TryParse(src.Data[i].ToString(), out entry))
+                    {
+                        ret.Add(entry);
+                    }
+                }
+                return ret;
+            }
+
+            public double Sum()
+            {
+                double sum = 0;
+                double entry;
+                for (int i = 0; i < Data.Length; i++)
+                {
+                    if (double.TryParse(Data[i].ToString(), out entry))
+                    {
+                        sum = sum + entry;
+                    }
+                }
+                return sum;
+            }
+
+            public double SumSqrs()
+            {
+                double sum = 0;
+                double entry;
+                for (int i = 0; i < Data.Length; i++)
+                {
+                    if (double.TryParse(Data[i].ToString(), out entry))
+                    {
+                        sum = sum + Math.Pow(entry, 2);
+                    }
+                }
+                return sum;
+            }
+
+            public double Mean()
+            {
+                return (this.Sum() / this.NumericLength());
+            }
+
+            public void NumericSort()
+            {
+                IComparer Numeric = new NumericComparer();
+                Array.Sort(Data, Numeric);
+            }
+
+            public void AlphaSort()
+            {
+                IComparer Alpha = new AlphaCompare();
+                Array.Sort(Data, Alpha);
+            }
+
+            public double Median()
+            {
+                return Qi(0.5);
+            }
+
+            public double GeometricMean()
+            {
+                double ret = 1.0;
+                list nums = ToDoubleList(this);
+                for (int i = 0; i < nums.Data.Length; i++)
+                {
+                    ret *= (double)nums.Data[i];
+                }
+                return Math.Exp(Math.Log(ret) / (double)nums.Data.Length);
+            }
+
+            public double HarmonicMean()
+            {
+                double ret = 0.0;
+                list nums = ToDoubleList(this);
+                for (int i = 0; i < nums.Data.Length; i++)
+                {
+                    ret += 1.0 / (double)nums.Data[i];
+                }
+                return ((double)nums.Data.Length / ret);
+            }
+
+            public double Variance()
+            {
+                double s = 0;
+                list num = ToDoubleList(this);
+                for (int i = 0; i < num.Data.Length; i++)
+                {
+                    s += Math.Pow((double)num.Data[i], 2);
+                }
+                return (s - num.Data.Length * Math.Pow(num.Mean(), 2)) / (num.Data.Length - 1);
+            }
+
+            public double StdDev()
+            {
+                return Math.Sqrt(this.Variance());
+            }
+
+            public double Qi(double i)
+            {
+                list j = this;
+                j.NumericSort();
+
+                if (Math.Ceiling(this.Length * i) == this.Length * i)
+                {
+                    return (double)((double)j.Data[(int)(this.Length * i - 1)] + (double)j.Data[(int)(this.Length * i)]) / 2;
+                }
+                else
+                {
+                    return (double)j.Data[((int)(Math.Ceiling(this.Length * i))) - 1];
+                }
+            }
+
+            #endregion
+
+            public string ToPrettyString()
+            {
+                string output;
+                if (m_data.Length == 0)
+                {
+                    return "[]";
+                }
+                output = "[";
+                foreach (object o in m_data)
+                {
+                    if (o is String)
+                    {
+                        output = output + "\"" + o + "\", ";
+                    }
+                    else
+                    {
+                        output = output + o.ToString() + ", ";
+                    }
+                }
+                output = output.Substring(0, output.Length - 2);
+                output = output + "]";
+                return output;
+            }
+
+            public class AlphaCompare : IComparer
+            {
+                int IComparer.Compare(object x, object y)
+                {
+                    return string.Compare(x.ToString(), y.ToString());
+                }
+            }
+
+            public class NumericComparer : IComparer
+            {
+                int IComparer.Compare(object x, object y)
+                {
+                    double a;
+                    double b;
+                    if (!double.TryParse(x.ToString(), out a))
+                    {
+                        a = 0.0;
+                    }
+                    if (!double.TryParse(y.ToString(), out b))
+                    {
+                        b = 0.0;
+                    }
+                    if (a < b)
+                    {
+                        return -1;
+                    }
+                    else if (a == b)
+                    {
+                        return 0;
+                    }
+                    else
+                    {
+                        return 1;
+                    }
+                }
+            }
+
+        }
+
+        //
+        // BELOW IS WORK IN PROGRESS... IT WILL CHANGE, SO DON'T USE YET! :)
+        //
+
+        public struct StringTest
+        {
+            // Our own little string
+            internal string actualString;
+            public static implicit operator bool(StringTest mString)
+            {
+                if (mString.actualString.Length == 0)
+                    return true;
+                return false;
+            }
+            public override string ToString()
+            {
+                return actualString;
+            }
+
+        }
+
+        [Serializable]
+        public struct key
+        {
+            public string value;
+
+            #region Constructors
+            public key(string s)
+            {
+                value = s;
+            }
+
+            #endregion
+
+            #region Methods
+
+            static public bool Parse2Key(string s)
+            {
+                Regex isuuid = new Regex(@"^[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}$", RegexOptions.Compiled);
+                if (isuuid.IsMatch(s))
+                {
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
+            #endregion
+
+            #region Operators
+
+            static public implicit operator Boolean(key k)
+            {
+                if (k.value.Length == 0)
+                {
+                    return false;
+                }
+
+                if (k.value == "00000000-0000-0000-0000-000000000000")
+                {
+                    return false;
+                }
+                Regex isuuid = new Regex(@"^[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}$", RegexOptions.Compiled);
+                if (isuuid.IsMatch(k.value))
+                {
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+
+            static public implicit operator key(string s)
+            {
+                return new key(s);
+            }
+
+            static public implicit operator String(key k)
+            {
+                return k.value;
+            }
+
+            public static bool operator ==(key k1, key k2)
+            {
+                return k1.value == k2.value;
+            }
+            public static bool operator !=(key k1, key k2)
+            {
+                return k1.value != k2.value;
+            }
+
+            #endregion
+
+            #region Overriders
+
+            public override bool Equals(object o)
+            {
+                return o.ToString() == value;
+            }
+
+            public override int GetHashCode()
+            {
+                return value.GetHashCode();
+            }
+
+            #endregion
+        }
+
+        [Serializable]
+        public struct LSLString
+        {
+            public string m_string;
+            #region Constructors
+            public LSLString(string s)
+            {
+                m_string = s;
+            }
+
+            public LSLString(int i)
+            {
+                m_string=i.ToString();
+            }
+
+            public LSLString(double d)
+            {
+                string s=String.Format("{0:0.000000}", d);
+                m_string=s;
+            }
+
+            #endregion
+
+            #region Operators
+            static public implicit operator Boolean(LSLString s)
+            {
+                if (s.m_string.Length == 0)
+                {
+                    return false;
+                }
+                else
+                {
+                    return true;
+                }
+            }
+
+
+
+            static public implicit operator String(LSLString s)
+            {
+                return s.m_string;
+            }
+
+            static public implicit operator LSLString(string s)
+            {
+                return new LSLString(s);
+            }
+
+            public static string ToString(LSLString s)
+            {
+                return s.m_string;
+            }
+
+            public override string ToString()
+            {
+                return m_string;
+            }
+
+            public static bool operator ==(LSLString s1, string s2)
+            {
+                return s1.m_string == s2;
+            }
+
+            public static bool operator !=(LSLString s1, string s2)
+            {
+                return s1.m_string != s2;
+            }
+
+            public static explicit operator double(LSLString s)
+            {
+                return Convert.ToDouble(s.m_string);
+            }
+
+            public static explicit operator LSLInteger(LSLString s)
+            {
+                return new LSLInteger(Convert.ToInt32(s.m_string));
+            }
+
+            public static explicit operator LSLString(int i)
+            {
+                return new LSLString(i);
+            }
+
+            public static explicit operator LSLString(double d)
+            {
+                return new LSLString(d);
+            }
+
+            public static implicit operator Vector3(LSLString s)
+            {
+                return new Vector3(s.m_string);
+            }
+
+            #endregion
+
+            #region Overriders
+            public override bool Equals(object o)
+            {
+                return m_string == o.ToString();
+            }
+
+            public override int GetHashCode()
+            {
+                return m_string.GetHashCode();
+            }
+
+            #endregion
+
+            #region " Standard string functions "
+            //Clone,CompareTo,Contains
+            //CopyTo,EndsWith,Equals,GetEnumerator,GetHashCode,GetType,GetTypeCode
+            //IndexOf,IndexOfAny,Insert,IsNormalized,LastIndexOf,LastIndexOfAny
+            //Length,Normalize,PadLeft,PadRight,Remove,Replace,Split,StartsWith,Substring,ToCharArray,ToLowerInvariant
+            //ToString,ToUpper,ToUpperInvariant,Trim,TrimEnd,TrimStart
+            public bool Contains(string value) { return m_string.Contains(value); }
+            public int IndexOf(string value) { return m_string.IndexOf(value); }
+            public int Length { get { return m_string.Length; } }
+
+
+            #endregion
+        }
+
+        [Serializable]
+        public struct LSLInteger
+        {
+            public int value;
+
+            #region Constructors
+            public LSLInteger(int i)
+            {
+                value = i;
+            }
+
+            public LSLInteger(double d)
+            {
+                value = (int)d;
+            }
+
+            public LSLInteger(Object o)
+            {
+                if(!(o is Int32))
+                    value=0;
+                else
+                    value = (int)o;
+            }
+
+            public LSLInteger(string s)
+            {
+                value = int.Parse(s);
+            }
+
+            #endregion
+
+            static public implicit operator int(LSLInteger i)
+            {
+                return i.value;
+            }
+
+            static public implicit operator uint(LSLInteger i)
+            {
+                return (uint)i.value;
+            }
+
+            static public explicit operator LSLString(LSLInteger i)
+            {
+                return new LSLString(i.ToString());
+            }
+
+            static public explicit operator string(LSLInteger i)
+            {
+                return i.ToString();
+            }
+
+            static public implicit operator Boolean(LSLInteger i)
+            {
+                if (i.value == 0)
+                {
+                    return false;
+                }
+                else
+                {
+                    return true;
+                }
+            }
+
+            static public implicit operator LSLInteger(int i)
+            {
+                return new LSLInteger(i);
+            }
+
+            static public explicit operator LSLInteger(string s)
+            {
+                return new LSLInteger(int.Parse(s));
+            }
+
+            static public implicit operator LSLInteger(double d)
+            {
+                return new LSLInteger(d);
+            }
+
+            static public bool operator ==(LSLInteger i1, LSLInteger i2)
+            {
+                bool ret = i1.value == i2.value;
+                return ret;
+            }
+
+            static public bool operator !=(LSLInteger i1, LSLInteger i2)
+            {
+                bool ret = i1.value != i2.value;
+                return ret;
+            }
+
+            static public LSLInteger operator &(LSLInteger i1, LSLInteger i2)
+            {
+                int ret = i1.value & i2.value;
+                return ret;
+            }
+
+            public static LSLInteger operator ++(LSLInteger i)
+            {
+                i.value++;
+                return i;
+            }
+
+
+            public static LSLInteger operator --(LSLInteger i)
+            {
+                i.value--;
+                return i;
+            }
+
+            static public implicit operator System.Double(LSLInteger i)
+            {
+                return (double)i.value;
+            }
+
+            public static bool operator true(LSLInteger i)
+            {
+                return i.value != 0;
+            }
+
+            public static bool operator false(LSLInteger i)
+            {
+                return i.value == 0;
+            }
+
+            #region Overriders
+
+            public override string ToString()
+            {
+                return this.value.ToString();
+            }
+
+            public override bool Equals(object o)
+            {
+                if(o is Int32)
+                {
+                    return value == (Int32)o;
+                }
+                if(o is LSLInteger)
+                {
+                    return value == ((LSLInteger)o).value;
+                }
+                return false;
+            }
+
+            public override int GetHashCode()
+            {
+                return value.GetHashCode();
+            }
+
+            #endregion
+        }
+
+        [Serializable]
+        public struct LSLFloat
+        {
+            public double value;
+
+            #region Constructors
+            public LSLFloat(int i)
+            {
+                this.value = (double)i;
+            }
+
+            public LSLFloat(double d)
+            {
+                this.value = d;
+            }
+
+            #endregion
+
+            #region Operators
+
+            static public implicit operator Double(LSLFloat f)
+            {
+                return f.value;
+            }
+
+            //static public implicit operator System.Int32(LSLFloat f)
+            //{
+            //    return (int)f.value;
+            //}
+
+
+            static public implicit operator Boolean(LSLFloat f)
+            {
+                if (f.value == 0)
+                {
+                    return false;
+                }
+                else
+                {
+                    return true;
+                }
+            }
+
+            static public implicit operator LSLFloat(int i)
+            {
+                return new LSLFloat(i);
+            }
+
+            static public implicit operator LSLFloat(double d)
+            {
+                return new LSLFloat(d);
+            }
+            #endregion
+
+            #region Overriders
+            public override string ToString()
+            {
+                return this.value.ToString();
+            }
+            #endregion
+        }
+    }
+}

+ 1435 - 0
OpenSim/Region/ScriptEngine/XEngine/XEngine.cs

@@ -0,0 +1,1435 @@
+using System;
+using System.IO;
+using System.Threading;
+using System.Collections;
+using System.Collections.Generic;
+using System.Security.Policy;
+using System.Reflection;
+using System.Xml;
+using libsecondlife;
+using log4net;
+using Nini.Config;
+using Amib.Threading;
+using OpenSim.Framework;
+using OpenSim.Region.Environment;
+using OpenSim.Region.Environment.Scenes;
+using OpenSim.Region.Environment.Interfaces;
+using OpenSim.Region.ScriptEngine.XEngine.Script;
+
+namespace OpenSim.Region.ScriptEngine.XEngine
+{
+    public class XEngine : IRegionModule
+    {
+        private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+        private SmartThreadPool m_ThreadPool;
+        private int m_MaxScriptQueue;
+        private Scene m_Scene;
+        private IConfig m_ScriptConfig;
+        private Compiler m_Compiler;
+        private EventManager m_EventManager;
+        private int m_EventLimit;
+        private bool m_KillTimedOutScripts;
+
+        private static List<XEngine> m_ScriptEngines =
+                new List<XEngine>();
+        public AsyncCommandManager m_ASYNCLSLCommandManager;
+
+        // Maps the local id to the script inventory items in it
+
+        private Dictionary<uint, List<LLUUID> > m_PrimObjects =
+                new Dictionary<uint, List<LLUUID> >();
+
+        // Maps the LLUUID above to the script instance
+
+        private Dictionary<LLUUID, XScriptInstance> m_Scripts =
+                new Dictionary<LLUUID, XScriptInstance>();
+
+        // Maps the asset ID to the assembly
+
+        private Dictionary<LLUUID, string> m_Assemblies =
+                new Dictionary<LLUUID, string>();
+
+        // This will list AppDomains by script asset
+
+        private Dictionary<LLUUID, AppDomain> m_AppDomains =
+                new Dictionary<LLUUID, AppDomain>();
+
+        // List the scripts running in each appdomain
+
+        private Dictionary<LLUUID, List<LLUUID> > m_DomainScripts =
+                new Dictionary<LLUUID, List<LLUUID> >();
+
+        public string ScriptEngineName
+        {
+            get { return "XEngine"; }
+        }
+
+        public Scene World
+        {
+            get { return m_Scene; }
+        }
+
+        public ILog Log
+        {
+            get { return m_log; }
+        }
+
+        public static List<XEngine> ScriptEngines
+        {
+            get { return m_ScriptEngines; }
+        }
+
+        private struct RezScriptParms
+        {
+            uint LocalID;
+            LLUUID ItemID;
+            string Script;
+        }
+
+        public IConfig ScriptConfigSource
+        {
+            get { return m_ScriptConfig; }
+        }
+
+        //
+        // IRegionModule functions
+        //
+        public void Initialise(Scene scene, IConfigSource configSource)
+        {
+            AppDomain.CurrentDomain.AssemblyResolve +=
+                    OnAssemblyResolve;
+
+            m_log.InfoFormat("[XEngine] Initializing scripts in region {0}",
+                    scene.RegionInfo.RegionName);
+            m_Scene=scene;
+
+            m_ScriptConfig = configSource.Configs["XEngine"];
+
+            if(m_ScriptConfig == null)
+            {
+                m_log.ErrorFormat("[XEngine] No script configuration found. Scripts disabled");
+                return;
+            }
+
+            int minThreads = m_ScriptConfig.GetInt("MinThreads", 2);
+            int maxThreads = m_ScriptConfig.GetInt("MaxThreads", 2);
+            int idleTimeout = m_ScriptConfig.GetInt("IdleTimeout", 60);
+            string priority = m_ScriptConfig.GetString("Priority", "BelowNormal");
+            int maxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300);
+            int stackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144);
+            int sleepTime = m_ScriptConfig.GetInt("MaintenanceInterval",
+                    10)*1000;
+            m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
+            m_KillTimedOutScripts = m_ScriptConfig.GetBoolean(
+                    "KillTimedOutScripts", false);
+            int saveTime = m_ScriptConfig.GetInt("SaveInterval", 300)*1000;
+
+            ThreadPriority prio = ThreadPriority.BelowNormal;
+            switch(priority)
+            {
+            case "Lowest":
+                prio=ThreadPriority.Lowest;
+                break;
+            case "BelowNormal":
+                prio=ThreadPriority.BelowNormal;
+                break;
+            case "Normal":
+                prio=ThreadPriority.Normal;
+                break;
+            case "AboveNormal":
+                prio=ThreadPriority.AboveNormal;
+                break;
+            case "Highest":
+                prio=ThreadPriority.Highest;
+                break;
+            default:
+                m_log.ErrorFormat("[XEngine] Invalid thread priority: '"+
+                        priority+"'. Assuming BelowNormal");
+                break;
+            }
+
+            lock(m_ScriptEngines)
+            {
+                m_ScriptEngines.Add(this);
+            }
+
+            m_EventManager = new EventManager(this);
+            m_ASYNCLSLCommandManager = new AsyncCommandManager(this);
+
+            StartEngine(minThreads, maxThreads, idleTimeout, prio,
+                    maxScriptQueue, stackSize);
+
+            m_Compiler = new Compiler(this);
+
+            m_Scene.EventManager.OnRezScript += OnRezScript;
+            m_Scene.EventManager.OnRemoveScript += OnRemoveScript;
+            m_Scene.EventManager.OnScriptReset += OnScriptReset;
+
+            if(sleepTime > 0)
+            {
+                m_ThreadPool.QueueWorkItem(new WorkItemCallback(
+                        this.DoMaintenance), new Object[] 
+                        { sleepTime });
+            }
+
+            if(saveTime > 0)
+            {
+                m_ThreadPool.QueueWorkItem(new WorkItemCallback(
+                        this.DoBackup), new Object[] { saveTime });
+            }
+        }
+
+        public void PostInitialise()
+        {
+            m_ThreadPool.Start();
+        }
+
+        public void Close()
+        {
+            lock(m_ScriptEngines)
+            {
+                if(m_ScriptEngines.Contains(this))
+                    m_ScriptEngines.Remove(this);
+            }
+        }
+
+        public object DoBackup(object o)
+        {
+            Object[] p = (Object[])o;
+            int saveTime = (int)p[0];
+
+            System.Threading.Thread.Sleep(saveTime);
+
+//            m_log.Debug("[XEngine] Backing up script states");
+
+            List<XScriptInstance> instances = new List<XScriptInstance>();
+
+            lock(m_Scripts)
+            {
+                foreach (XScriptInstance instance in m_Scripts.Values)
+                    instances.Add(instance);
+            }
+
+            foreach (XScriptInstance i in instances)
+            {
+                string assembly = String.Empty;
+
+                lock(m_Scripts)
+                {
+                    if(!m_Assemblies.ContainsKey(i.AssetID))
+                        continue;
+                    assembly = m_Assemblies[i.AssetID];
+                }
+
+                i.SaveState(assembly);
+            }
+
+            instances.Clear();
+
+            m_ThreadPool.QueueWorkItem(new WorkItemCallback(
+                    this.DoBackup), new Object[] { saveTime });
+
+            return 0;
+        }
+
+        public object DoMaintenance(object p)
+        {
+            object[] parms = (object[])p;
+            int sleepTime = (int)parms[0];
+
+            foreach (XScriptInstance inst in m_Scripts.Values)
+            {
+                if(inst.EventTime() > m_EventLimit)
+                {
+                    inst.Stop(100);
+                    if(!m_KillTimedOutScripts)
+                        inst.Start();
+                }
+            }
+
+            System.Threading.Thread.Sleep(sleepTime);
+
+            m_ThreadPool.QueueWorkItem(new WorkItemCallback(
+                    this.DoMaintenance), new Object[] 
+                    { sleepTime });
+
+            return 0;
+        }
+
+        public string Name
+        {
+            get { return "XEngine"; }
+        }
+
+        public bool IsSharedModule
+        {
+            get { return false; }
+        }
+
+        //
+        // XEngine functions
+        //
+        public int MaxScriptQueue
+        {
+            get { return m_MaxScriptQueue; }
+        }
+
+        //
+        // Hooks
+        //
+        public void OnRezScript(uint localID, LLUUID itemID, string script)
+        {
+            m_ThreadPool.QueueWorkItem(new WorkItemCallback(
+                    this.DoOnRezScript), new Object[] 
+                    { localID, itemID, script});
+        }
+
+        private object DoOnRezScript(object parm)
+        {
+            Object[] p = (Object[])parm;
+            uint localID = (uint)p[0];
+            LLUUID itemID = (LLUUID)p[1];
+            string script =(string)p[2];
+
+            // Get the asset ID of the script, so we can check if we
+            // already have it.
+
+            SceneObjectPart part = m_Scene.GetSceneObjectPart(localID);
+            if(part == null)
+                return false;
+
+            TaskInventoryItem item = part.GetInventoryItem(itemID);
+            if(item == null)
+                return false;
+            
+            LLUUID assetID=item.AssetID;
+
+//            m_log.DebugFormat("[XEngine] Compiling script {0} ({1})",
+//                    item.Name, itemID.ToString());
+
+            string assembly="";
+            try
+            {
+                assembly=m_Compiler.PerformScriptCompile(script,
+                        assetID.ToString());
+                m_log.DebugFormat("[XEngine] Loaded script {0}.{1}",
+                        part.ParentGroup.RootPart.Name, item.Name);
+            }
+            catch (Exception e)
+            {
+                try
+                {
+                    // DISPLAY ERROR INWORLD
+                    string text = "Error compiling script:\r\n" + e.Message.ToString();
+                    if (text.Length > 1400)
+                        text = text.Substring(0, 1400);
+                    World.SimChat(Helpers.StringToField(text),
+                            ChatTypeEnum.DebugChannel, 2147483647,
+                            part.AbsolutePosition,
+                            part.Name, part.UUID, false);
+                }
+                catch (Exception e2) // LEGIT: User Scripting
+                {
+                    m_log.Error("[XEngine]: "+
+                            "Error displaying error in-world: " +
+                            e2.ToString());
+                    m_log.Error("[XEngine]: " +
+                            "Errormessage: Error compiling script:\r\n" +
+                            e.Message.ToString());
+                }
+
+                return false;
+            }
+
+            lock(m_Scripts)
+            {
+                // Create the object record
+                
+                if(!m_PrimObjects.ContainsKey(localID))
+                    m_PrimObjects[localID] = new List<LLUUID>();
+
+                if(!m_PrimObjects[localID].Contains(itemID))
+                    m_PrimObjects[localID].Add(itemID);
+
+                if(!m_Assemblies.ContainsKey(assetID))
+                    m_Assemblies[assetID] = assembly;
+
+                if((!m_Scripts.ContainsKey(itemID)) ||
+                   (m_Scripts[itemID].AssetID != assetID))
+                {
+                    LLUUID appDomain=assetID;
+
+                    if(part.ParentGroup.RootPart.m_IsAttachment)
+                        appDomain=part.ParentGroup.RootPart.UUID;
+                    
+                    if(!m_AppDomains.ContainsKey(appDomain))
+                    {
+                        try
+                        {
+                            AppDomainSetup appSetup = new AppDomainSetup();
+//                            appSetup.ApplicationBase = Path.Combine(
+//                                    "ScriptEngines",
+//                                    m_Scene.RegionInfo.RegionID.ToString());
+
+                            Evidence baseEvidence =
+                                    AppDomain.CurrentDomain.Evidence;
+                            Evidence evidence = new Evidence(baseEvidence);
+
+                            m_AppDomains[appDomain] =
+                                AppDomain.CreateDomain(
+                                        m_Scene.RegionInfo.RegionID.ToString(),
+                                        evidence, appSetup);
+
+                            m_AppDomains[appDomain].AssemblyResolve +=
+                                    new ResolveEventHandler(
+                                    AssemblyResolver.OnAssemblyResolve);
+                            m_DomainScripts[appDomain] = new List<LLUUID>();
+                        }
+                        catch (Exception e)
+                        {
+                            m_log.Error("[XEngine] Exception creating app domain:\n"+e.ToString());
+                            return false;
+                        }
+                    }
+                    m_DomainScripts[appDomain].Add(itemID);
+
+
+                    XScriptInstance instance = new XScriptInstance(this,localID,
+                            part.UUID, itemID, assetID, assembly,
+                            m_AppDomains[appDomain]);
+
+                    instance.AppDomain = appDomain;
+
+                    m_Scripts[itemID] = instance;
+                }
+            }
+            return true;
+        }
+
+        public void OnRemoveScript(uint localID, LLUUID itemID)
+        {
+            lock(m_Scripts)
+            {
+                // Do we even have it?
+                if(!m_Scripts.ContainsKey(itemID))
+                    return;
+
+                m_ASYNCLSLCommandManager.RemoveScript(localID, itemID);
+
+                XScriptInstance instance=m_Scripts[itemID];
+                m_Scripts.Remove(itemID);
+
+                instance.ClearQueue();
+                instance.Stop(0);
+
+                SceneObjectPart part =
+                        m_Scene.GetSceneObjectPart(localID);
+
+                if(part != null)
+                    part.RemoveScriptEvents(itemID);
+
+                // Remove the script from it's prim
+                if(m_PrimObjects.ContainsKey(localID))
+                {
+                    // Remove inventory item record
+                    if(m_PrimObjects[localID].Contains(itemID))
+                        m_PrimObjects[localID].Remove(itemID);
+
+                    // If there are no more scripts, remove prim
+                    if(m_PrimObjects[localID].Count == 0)
+                    {
+                        m_PrimObjects.Remove(localID);
+                    }
+                }
+
+                m_DomainScripts[instance.AppDomain].Remove(instance.ItemID);
+                if(m_DomainScripts[instance.AppDomain].Count == 0)
+                {
+                    m_DomainScripts.Remove(instance.AppDomain);
+                    UnloadAppDomain(instance.AppDomain);
+                }
+
+                instance = null;
+
+                CleanAssemblies();
+            }
+        }
+
+        public void OnScriptReset(uint localID, LLUUID itemID)
+        {
+            ResetScript(itemID);
+        }
+
+        private void CleanAssemblies()
+        {
+            List<LLUUID> assetIDList = new List<LLUUID>(m_Assemblies.Keys);
+
+            foreach (XScriptInstance i in m_Scripts.Values)
+            {
+                if(assetIDList.Contains(i.AssetID))
+                    assetIDList.Remove(i.AssetID);
+            }
+
+            foreach (LLUUID assetID in assetIDList)
+            {
+//                m_log.DebugFormat("[XEngine] Removing unreferenced assembly {0}", m_Assemblies[assetID]);
+                try
+                {
+                    if(File.Exists(m_Assemblies[assetID]))
+                        File.Delete(m_Assemblies[assetID]);
+                    if(File.Exists(m_Assemblies[assetID]+".state"))
+                        File.Delete(m_Assemblies[assetID]+".state");
+                    if(File.Exists(m_Assemblies[assetID]+".mdb"))
+                        File.Delete(m_Assemblies[assetID]+".mdb");
+                }
+                catch (Exception e)
+                {
+                }
+                m_Assemblies.Remove(assetID);
+            }
+        }
+
+        private void UnloadAppDomain(LLUUID id)
+        {
+            if(m_AppDomains.ContainsKey(id))
+            {
+                AppDomain domain=m_AppDomains[id];
+                m_AppDomains.Remove(id);
+
+                AppDomain.Unload(domain);
+                domain = null;
+//                m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString());
+            }
+        }
+
+        //
+        // Start processing
+        //
+        private void StartEngine(int minThreads, int maxThreads,
+                int idleTimeout, ThreadPriority threadPriority,
+                int maxScriptQueue, int stackSize)
+        {
+            m_MaxScriptQueue=maxScriptQueue;
+
+            STPStartInfo startInfo = new STPStartInfo();
+            startInfo.IdleTimeout = idleTimeout;
+            startInfo.MaxWorkerThreads = maxThreads;
+            startInfo.MinWorkerThreads = minThreads;
+            startInfo.ThreadPriority = threadPriority;
+            startInfo.StackSize = stackSize;
+            startInfo.StartSuspended = true;
+            
+            m_ThreadPool = new SmartThreadPool(startInfo);
+        }
+
+        //
+        // Used by script instances to queue event handler jobs
+        //
+        public IWorkItemResult QueueEventHandler(object parms)
+        {
+            return m_ThreadPool.QueueWorkItem(new WorkItemCallback(
+                    this.ProcessEventHandler), parms);
+        }
+
+        //
+        // The main script engine worker
+        //
+        private object ProcessEventHandler(object parms)
+        {
+            XScriptInstance instance=(XScriptInstance)parms;
+            
+            return instance.EventProcessor();
+        }
+
+        //
+        // Post event to an entire prim
+        //
+        public bool PostObjectEvent(uint localID, XEventParams p)
+        {
+            bool result = false;
+
+            if(!m_PrimObjects.ContainsKey(localID))
+                return false;
+
+            foreach (LLUUID itemID in m_PrimObjects[localID])
+            {
+                if(m_Scripts.ContainsKey(itemID))
+                {
+                    XScriptInstance instance = m_Scripts[itemID];
+                    if(instance != null)
+                    {
+                        instance.PostEvent(p);
+                        result = true;
+                    }
+                }
+            }
+            return result;
+        }
+
+        //
+        // Post an event to a single script
+        //
+        public bool PostScriptEvent(LLUUID itemID, XEventParams p)
+        {
+            if(m_Scripts.ContainsKey(itemID))
+            {
+                XScriptInstance instance = m_Scripts[itemID];
+                if(instance != null)
+                    instance.PostEvent(p);
+                return true;
+            }
+            return false;
+        }
+
+        public Assembly OnAssemblyResolve(object sender,
+                ResolveEventArgs args)
+        {
+            if(!(sender is System.AppDomain))
+                return null;
+
+            string[] pathList=new string[] {"bin", "ScriptEngines",
+                    Path.Combine("ScriptEngines",
+                    m_Scene.RegionInfo.RegionID.ToString())};
+
+            string assemblyName = args.Name;
+            if(assemblyName.IndexOf(",") != -1)
+                assemblyName=args.Name.Substring(0, args.Name.IndexOf(","));
+
+            foreach (string s in pathList)
+            {
+                string path=Path.Combine(Directory.GetCurrentDirectory(),
+                        Path.Combine(s, assemblyName))+".dll";
+
+                if(File.Exists(path))
+                    return Assembly.LoadFrom(path);
+            }
+
+            return null;
+        }
+
+        private XScriptInstance GetInstance(LLUUID itemID)
+        {
+            XScriptInstance instance;
+            lock(m_Scripts)
+            {
+                if(!m_Scripts.ContainsKey(itemID))
+                    return null;
+                instance = m_Scripts[itemID];
+            }
+            return instance;
+        }
+
+        public void SetScriptState(LLUUID itemID, bool running)
+        {
+            XScriptInstance instance = GetInstance(itemID);
+            if(instance != null)
+            {
+                if(running)
+                    instance.Start();
+                else
+                    instance.Stop(500);
+            }
+        }
+
+        public bool GetScriptState(LLUUID itemID)
+        {
+            XScriptInstance instance = GetInstance(itemID);
+            if(instance != null)
+                return instance.Running;
+            return false;
+        }
+
+        public void ResetScript(LLUUID itemID)
+        {
+            XScriptInstance instance = GetInstance(itemID);
+            if(instance != null)
+                instance.ResetScript();
+        }
+
+        public XDetectParams GetDetectParams(LLUUID itemID, int idx)
+        {
+            XScriptInstance instance = GetInstance(itemID);
+            if(instance != null)
+                return instance.GetDetectParams(idx);
+            return new XDetectParams();
+        }
+
+        public LLUUID GetDetectID(LLUUID itemID, int idx)
+        {
+            XScriptInstance instance = GetInstance(itemID);
+            if(instance != null)
+                return instance.GetDetectID(idx);
+            return LLUUID.Zero;
+        }
+    }
+
+    public struct XDetectParams
+    {
+        public LLUUID Key;
+        public LSL_Types.Vector3 OffsetPos;
+    }
+
+    public class XEventParams
+    {
+        public XEventParams(string eventName, Object[] eventParams, XDetectParams[] detectParams)
+        {
+            EventName=eventName;
+            Params=eventParams;
+            DetectParams=detectParams;
+        }
+
+        public string EventName;
+        public Object[] Params;
+        public XDetectParams[] DetectParams;
+    }
+
+    public class XScriptInstance
+    {
+        private XEngine m_Engine;
+        private IWorkItemResult m_CurrentResult=null;
+        private Queue m_EventQueue=new Queue(32);
+        private bool m_RunEvents=false;
+        private LLUUID m_ItemID;
+        private uint m_LocalID;
+        private LLUUID m_ObjectID;
+        private LLUUID m_AssetID;
+        private IScript m_Script;
+        private LSL_ScriptCommands m_LSLCommands;
+        private OSSL_ScriptCommands m_OSSLCommands;
+        private Executor m_Executor;
+        private LLUUID m_AppDomain;
+        private XDetectParams[] m_DetectParams;
+        private bool m_TimerQueued;
+        private DateTime m_EventStart;
+        private bool m_InEvent;
+
+        // Script state
+        private string m_State="default";
+
+        public Object[] PluginData = new Object[0];
+
+        public bool Running
+        {
+            get { return m_RunEvents; }
+        }
+
+        public string State
+        {
+            get { return m_State; }
+            set { m_State = value; }
+        }
+
+        public XEngine Engine
+        {
+            get { return m_Engine; }
+        }
+
+        public LLUUID AppDomain
+        {
+            get { return m_AppDomain; }
+            set { m_AppDomain = value; }
+        }
+
+        public LLUUID ItemID
+        {
+            get { return m_ItemID; }
+        }
+
+        public LLUUID ObjectID
+        {
+            get { return m_ObjectID; }
+        }
+
+        public uint LocalID
+        {
+            get { return m_LocalID; }
+        }
+
+        public LLUUID AssetID
+        {
+            get { return m_AssetID; }
+        }
+
+        public Queue EventQueue
+        {
+            get { return m_EventQueue; }
+        }
+
+        public void ClearQueue()
+        {
+            m_TimerQueued = false;
+            m_EventQueue.Clear();
+        }
+
+        public XScriptInstance(XEngine engine, uint localID, LLUUID objectID,
+                LLUUID itemID, LLUUID assetID, string assembly, AppDomain dom)
+        {
+            m_Engine=engine;
+
+            m_LocalID = localID;
+            m_ObjectID = objectID;
+            m_ItemID = itemID;
+            m_AssetID = assetID;
+
+            SceneObjectPart part=engine.World.GetSceneObjectPart(localID);
+            if(part == null)
+            {
+                engine.Log.Error("[XEngine] SceneObjectPart unavailable. Script NOT started.");
+                return;
+            }
+
+            m_LSLCommands = new LSL_ScriptCommands(engine, this, part, localID,
+                    itemID);
+            m_OSSLCommands = new OSSL_ScriptCommands(engine, this, part,
+                    localID, itemID);
+
+            try
+            {
+                m_Script = (IScript)dom.CreateInstanceAndUnwrap(
+                        Path.GetFileNameWithoutExtension(assembly),
+                        "SecondLife.Script");
+            }
+            catch (Exception e)
+            {
+                m_Engine.Log.ErrorFormat("[XEngine] Error loading assembly {0}\n"+e.ToString(), assembly);
+            }
+
+            try
+            {
+                m_Script.Start(m_LSLCommands, m_OSSLCommands);
+
+                m_Executor = new Executor(m_Script);
+
+//                m_Engine.Log.Debug("[XEngine] Script instance created");
+
+                part.SetScriptEvents(m_ItemID,
+                        (int)m_Executor.GetStateEventFlags());
+            }
+            catch (Exception e)
+            {
+                m_Engine.Log.Error("Error loading script instance\n"+e.ToString());
+            }
+
+            string savedState = assembly+".state";
+            if(File.Exists(savedState))
+            {
+                string xml = String.Empty;
+
+                try
+                {
+                    FileInfo fi = new FileInfo(savedState);
+                    int size=(int)fi.Length;
+                    if(size < 130000)
+                    {
+                        using (FileStream fs = File.Open(savedState,
+                                FileMode.Open, FileAccess.Read, FileShare.None))
+                        {
+                            System.Text.ASCIIEncoding enc =
+                                    new System.Text.ASCIIEncoding();
+
+                            Byte[] data=new Byte[size];
+                            fs.Read(data, 0, size);
+
+                            xml=enc.GetString(data);
+
+                            ScriptSerializer.Deserialize(xml, this);
+
+                            m_Engine.m_ASYNCLSLCommandManager.CreateFromData(
+                                    m_LocalID, m_ItemID, m_ObjectID,
+                                    PluginData);
+                        }
+                    }
+                    else
+                    {
+                        m_Engine.Log.Error("Unable to load script state: Memory limit exceeded");
+                        PostEvent(new XEventParams("state_entry",
+                                new Object[0], new XDetectParams[0]));
+                    }
+                }
+                catch (Exception e)
+                {
+                    m_Engine.Log.ErrorFormat("Unable to load script state from xml: {0}\n"+e.ToString(), xml);
+                    PostEvent(new XEventParams("state_entry",
+                            new Object[0], new XDetectParams[0]));
+                }
+            }
+            else
+            {
+                PostEvent(new XEventParams("state_entry",
+                        new Object[0], new XDetectParams[0]));
+            }
+            Start();
+        }
+
+        public void VarDump(Dictionary<string, object> vars)
+        {
+            Console.WriteLine("Variable dump for script {0}", m_ItemID.ToString());
+            foreach (KeyValuePair<string, object> v in vars)
+            {
+                Console.WriteLine("Variable: {0} = '{1}'", v. Key,
+                        v.Value.ToString());
+            }
+        }
+
+        public void Start()
+        {
+            lock(m_EventQueue)
+            {
+                if(Running)
+                    return;
+
+                m_RunEvents=true;
+
+                if(m_EventQueue.Count > 0)
+                {
+                    if(m_CurrentResult == null)
+                        m_CurrentResult=m_Engine.QueueEventHandler(this);
+                }
+            }
+        }
+
+        public bool Stop(int timeout)
+        {
+            IWorkItemResult result;
+
+            lock(m_EventQueue)
+            {
+                if(!Running)
+                    return true;
+
+                if(m_CurrentResult == null)
+                {
+                    m_RunEvents=false;
+                    return true;
+                }
+
+                if(m_CurrentResult.Cancel())
+                {
+                    m_CurrentResult=null;
+                    m_RunEvents=false;
+                    return true;
+                }
+
+                result=m_CurrentResult;
+                m_RunEvents=false;
+            }
+
+            if(SmartThreadPool.WaitAll(new IWorkItemResult[] {result}, new TimeSpan((long)timeout*100000), false))
+            {
+                return true;
+            }
+
+            lock(m_EventQueue)
+            {
+                if(m_CurrentResult != null)
+                    m_CurrentResult.Abort();
+                else
+                    return true;
+            }
+
+            return true;
+        }
+
+        public void SetState(string state)
+        {
+            PostEvent(new XEventParams("state_exit", new Object[0],
+                    new XDetectParams[0]));
+            PostEvent(new XEventParams("state", new Object[] { state },
+                    new XDetectParams[0]));
+            PostEvent(new XEventParams("state_entry", new Object[0],
+                    new XDetectParams[0]));
+        }
+
+        public void PostEvent(XEventParams data)
+        {
+            lock(m_EventQueue)
+            {
+                if(m_EventQueue.Count >= m_Engine.MaxScriptQueue)
+                    return;
+
+                m_EventQueue.Enqueue(data);
+                if(data.EventName == "timer")
+                {
+                    if(m_TimerQueued)
+                        return;
+                    m_TimerQueued = true;
+                }
+
+                if(!m_RunEvents)
+                    return;
+
+                if(m_CurrentResult == null)
+                {
+                    m_CurrentResult=m_Engine.QueueEventHandler(this);
+                }
+            }
+        }
+
+        public object EventProcessor()
+        {
+            XEventParams data=null;
+
+            lock(m_EventQueue)
+            {
+                data=(XEventParams)m_EventQueue.Dequeue();
+                if(data == null) // Shouldn't happen
+                {
+                    m_CurrentResult=null;
+                    return 0;
+                }
+                if(data.EventName == "timer")
+                    m_TimerQueued = false;
+            }
+
+            m_DetectParams=data.DetectParams;
+
+            if(data.EventName == "state") // Hardcoded state change
+            {
+                m_State=data.Params[0].ToString();
+                m_Engine.m_ASYNCLSLCommandManager.RemoveScript(
+                        m_LocalID, m_ItemID);
+
+                SceneObjectPart part=m_Engine.World.GetSceneObjectPart(
+                        m_LocalID);
+                if(part != null)
+                {
+                    part.SetScriptEvents(m_ItemID,
+                            (int)m_Executor.GetStateEventFlags());
+                }
+            }
+            else
+            {
+//                m_Engine.Log.DebugFormat("[XEngine] Processed event {0}", data.EventName);
+                SceneObjectPart part=m_Engine.World.GetSceneObjectPart(
+                        m_LocalID);
+                try
+                {
+                    m_EventStart = DateTime.Now;
+                    m_InEvent = true;
+                    m_Executor.ExecuteEvent(data.EventName, data.Params);
+                    m_InEvent = false;
+                }
+                catch (Exception e)
+                {
+                    m_InEvent = false;
+                    if(e is System.Threading.ThreadAbortException)
+                    {
+                        lock(m_EventQueue)
+                        {
+                            if((m_EventQueue.Count > 0) && m_RunEvents)
+                            {
+                                m_CurrentResult=m_Engine.QueueEventHandler(this);
+                            }
+                            else
+                            {
+                                m_CurrentResult=null;
+                            }
+                        }
+
+                        m_DetectParams=null;
+
+                        return 0;
+                    }
+
+                    try
+                    {
+                        // DISPLAY ERROR INWORLD
+                        string text = "Runtime error:\n" + e.ToString();
+                        if (text.Length > 1400)
+                            text = text.Substring(0, 1400);
+                        m_Engine.World.SimChat(Helpers.StringToField(text),
+                                ChatTypeEnum.DebugChannel, 2147483647,
+                                part.AbsolutePosition,
+                                part.Name, part.UUID, false);
+                    }
+                    catch (Exception e2) // LEGIT: User Scripting
+                    {
+                        m_Engine.Log.Error("[XEngine]: "+
+                                "Error displaying error in-world: " +
+                                e2.ToString());
+                        m_Engine.Log.Error("[XEngine]: " +
+                                "Errormessage: Error compiling script:\r\n" +
+                                e.ToString());
+                    }
+                }
+            }
+
+            lock(m_EventQueue)
+            {
+                if((m_EventQueue.Count > 0) && m_RunEvents)
+                {
+                    m_CurrentResult=m_Engine.QueueEventHandler(this);
+                }
+                else
+                {
+                    m_CurrentResult=null;
+                }
+            }
+
+            m_DetectParams=null;
+
+            return 0;
+        }
+
+        public int EventTime()
+        {
+            if(!m_InEvent)
+                return 0;
+
+            return (DateTime.Now - m_EventStart).Seconds;
+        }
+
+        public void ResetScript()
+        {
+            Stop(0);
+            m_Engine.m_ASYNCLSLCommandManager.RemoveScript(m_LocalID, m_ItemID);
+            m_EventQueue.Clear();
+            m_Script.ResetVars();
+            m_State = "default";
+            Start();
+            PostEvent(new XEventParams("state_entry",
+                    new Object[0], new XDetectParams[0]));
+        }
+
+        public Dictionary<string, object> GetVars()
+        {
+            return m_Script.GetVars();
+        }
+
+        public void SetVars(Dictionary<string, object> vars)
+        {
+            m_Script.SetVars(vars);
+        }
+
+        public XDetectParams GetDetectParams(int idx)
+        {
+            if(idx < 0 || idx >= m_DetectParams.Length)
+                return new XDetectParams();
+
+            return m_DetectParams[idx];
+        }
+
+        public LLUUID GetDetectID(int idx)
+        {
+            if(idx < 0 || idx >= m_DetectParams.Length)
+                return LLUUID.Zero;
+
+            return m_DetectParams[idx].Key;
+        }
+
+        public void SaveState(string assembly)
+        {
+            PluginData =
+                    m_Engine.m_ASYNCLSLCommandManager.GetSerializationData(
+                    m_ItemID);
+
+            string xml=ScriptSerializer.Serialize(this);
+
+            try
+            {
+                FileStream fs = File.Create(assembly+".state");
+                System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
+                Byte[] buf=enc.GetBytes(xml);
+                fs.Write(buf, 0, buf.Length);
+                fs.Close();
+            }
+            catch(Exception)
+            {
+                return;
+            }
+        }
+    }
+
+    public class ScriptSerializer
+    {
+        public static string Serialize(XScriptInstance instance)
+        {
+            instance.Stop(50);
+
+            XmlDocument xmldoc = new XmlDocument();
+
+            XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
+                    "", "");
+            xmldoc.AppendChild(xmlnode);
+
+            XmlElement rootElement = xmldoc.CreateElement("", "ScriptState",
+                    "");
+            xmldoc.AppendChild(rootElement);
+
+            XmlElement state = xmldoc.CreateElement("", "State", "");
+            state.AppendChild(xmldoc.CreateTextNode(instance.State));
+
+            rootElement.AppendChild(state);
+
+            Dictionary<string, Object> vars = instance.GetVars();
+
+            XmlElement variables = xmldoc.CreateElement("", "Variables", "");
+
+            foreach (KeyValuePair<string, Object> var in vars)
+                WriteTypedValue(xmldoc, variables, "Variable", var.Key,
+                        var.Value);
+
+            rootElement.AppendChild(variables);
+
+            XmlElement queue = xmldoc.CreateElement("", "Queue", "");
+
+            int count = instance.EventQueue.Count;
+            
+            while(count > 0)
+            {
+                XEventParams ep = (XEventParams)instance.EventQueue.Dequeue();
+                instance.EventQueue.Enqueue(ep);
+                count--;
+
+                XmlElement item = xmldoc.CreateElement("", "Item", "");
+                XmlAttribute itemEvent = xmldoc.CreateAttribute("", "event",
+                        "");
+                itemEvent.Value=ep.EventName;
+                item.Attributes.Append(itemEvent);
+
+                XmlElement parms = xmldoc.CreateElement("", "Params", "");
+
+                foreach (Object o in ep.Params)
+                    WriteTypedValue(xmldoc, parms, "Param", String.Empty, o);
+
+                item.AppendChild(parms);
+
+                XmlElement detect = xmldoc.CreateElement("", "Detected", "");
+
+                foreach (XDetectParams det in ep.DetectParams)
+                {
+                    XmlElement objectElem = xmldoc.CreateElement("", "Object",
+                            "");
+                    XmlAttribute pos = xmldoc.CreateAttribute("", "pos", "");
+                    pos.Value=det.OffsetPos.ToString();
+                    objectElem.Attributes.Append(pos);
+                    objectElem.AppendChild(
+                            xmldoc.CreateTextNode(det.Key.ToString()));
+
+                    detect.AppendChild(objectElem);
+                }
+
+                item.AppendChild(detect);
+
+                queue.AppendChild(item);
+            }
+
+            rootElement.AppendChild(queue);
+
+            XmlNode plugins = xmldoc.CreateElement("", "Plugins", "");
+            if(instance.PluginData.Length > 0)
+                DumpList(xmldoc, plugins,
+                        new LSL_Types.list(instance.PluginData));
+
+            rootElement.AppendChild(plugins);
+
+            instance.Start();
+
+            return xmldoc.InnerXml;
+        }
+
+        public static void Deserialize(string xml, XScriptInstance instance)
+        {
+            XmlDocument doc = new XmlDocument();
+
+            Dictionary<string, object> vars = instance.GetVars();
+
+            instance.PluginData = new Object[0];
+
+            doc.LoadXml(xml);
+            
+            XmlNodeList rootL = doc.GetElementsByTagName("ScriptState");
+            if(rootL.Count != 1)
+            {
+                return;
+            }
+            XmlNode rootNode = rootL[0];
+
+            if(rootNode != null)
+            {
+                object varValue;
+                XmlNodeList partL = rootNode.ChildNodes;
+
+                foreach (XmlNode part in partL)
+                {
+                    switch(part.Name)
+                    {
+                    case "State":
+                        instance.State=part.InnerText;
+                        break;
+                    case "Variables":
+                        XmlNodeList varL = part.ChildNodes;
+                        foreach (XmlNode var in varL)
+                        {
+                            string varName;
+                            varValue=ReadTypedValue(var, out varName);
+
+                            if(vars.ContainsKey(varName))
+                                vars[varName] = varValue;
+                        }
+                        instance.SetVars(vars);
+                        break;
+                    case "Queue":
+                        XmlNodeList itemL = part.ChildNodes;
+                        foreach (XmlNode item in itemL)
+                        {
+                            List<Object> parms = new List<Object>();
+                            List<XDetectParams> detected =
+                                    new List<XDetectParams>();
+
+                            string eventName =
+                                    item.Attributes.GetNamedItem("event").Value;
+                            XmlNodeList eventL = item.ChildNodes;
+                            foreach (XmlNode evt in eventL)
+                            {
+                                switch(evt.Name)
+                                {
+                                case "Params":
+                                    XmlNodeList prms = evt.ChildNodes;
+                                    foreach (XmlNode pm in prms)
+                                        parms.Add(ReadTypedValue(pm));
+
+                                    break;
+                                case "Detected":
+                                    XmlNodeList detL = evt.ChildNodes;
+                                    foreach (XmlNode det in detL)
+                                    {
+                                        string vect =
+                                                det.Attributes.GetNamedItem(
+                                                "pos").Value;
+                                        LSL_Types.Vector3 v =
+                                                new LSL_Types.Vector3(vect);
+                                        LLUUID uuid = new LLUUID();
+                                        LLUUID.TryParse(det.InnerText,
+                                                out uuid);
+
+                                        XDetectParams d;
+                                        d.Key = uuid;
+                                        d.OffsetPos = v;
+
+                                        detected.Add(d);
+                                    }
+                                    break;
+                                }
+                            }
+                            XEventParams ep = new XEventParams(
+                                    eventName, parms.ToArray(),
+                                    detected.ToArray());
+                            instance.EventQueue.Enqueue(ep);
+                        }
+                        break;
+                    case "Plugins":
+                        instance.PluginData = ReadList(part).Data;
+                        break;
+                    }
+                }
+            }
+        }
+
+        private static void DumpList(XmlDocument doc, XmlNode parent,
+                LSL_Types.list l)
+        {
+            foreach (Object o in l.Data)
+                WriteTypedValue(doc, parent, "ListItem", "", o);
+        }
+
+        private static LSL_Types.list ReadList(XmlNode parent)
+        {
+            List<Object> olist = new List<Object>();
+
+            XmlNodeList itemL = parent.ChildNodes;
+            foreach(XmlNode item in itemL)
+                olist.Add(ReadTypedValue(item));
+
+            return new LSL_Types.list(olist.ToArray());
+        }
+
+        private static void WriteTypedValue(XmlDocument doc, XmlNode parent,
+                string tag, string name, object value)
+        {
+            Type t=value.GetType();
+            XmlAttribute typ = doc.CreateAttribute("", "type", "");
+            XmlNode n = doc.CreateElement("", tag, "");
+
+            if(value is LSL_Types.list)
+            {
+                typ.Value = "list";
+                n.Attributes.Append(typ);
+
+                DumpList(doc, n, (LSL_Types.list) value);
+
+                if(name != String.Empty)
+                {
+                    XmlAttribute nam = doc.CreateAttribute("", "name", "");
+                    nam.Value = name;
+                    n.Attributes.Append(nam);
+                }
+
+                parent.AppendChild(n);
+                return;
+            }
+
+            n.AppendChild(doc.CreateTextNode(value.ToString()));
+
+            typ.Value = t.ToString();
+            n.Attributes.Append(typ);
+            if(name != String.Empty)
+            {
+                XmlAttribute nam = doc.CreateAttribute("", "name", "");
+                nam.Value = name;
+                n.Attributes.Append(nam);
+            }
+
+            parent.AppendChild(n);
+        }
+
+        private static object ReadTypedValue(XmlNode tag, out string name)
+        {
+            name = tag.Attributes.GetNamedItem("name").Value;
+
+            return ReadTypedValue(tag);
+        }
+
+        private static object ReadTypedValue(XmlNode tag)
+        {
+            Object varValue;
+            string assembly;
+
+            string itemType = tag.Attributes.GetNamedItem("type").Value;
+
+            if(itemType == "list")
+                return ReadList(tag);
+
+            if(itemType == "libsecondlife.LLUUID")
+            {
+                LLUUID val = new LLUUID();
+                LLUUID.TryParse(tag.InnerText, out val);
+                
+                return val;
+            }
+
+            Type itemT = Type.GetType(itemType);
+            if(itemT == null)
+            {
+                Object[] args =
+                    new Object[] { tag.InnerText };
+
+                assembly = itemType+", OpenSim.Region.ScriptEngine.XEngine.Script";
+                itemT = Type.GetType(assembly);
+                if(itemT == null)
+                    return null;
+
+                varValue = Activator.CreateInstance(itemT, args);
+
+                if(varValue == null)
+                    return null;
+            }
+            else
+            {
+                varValue = Convert.ChangeType(tag.InnerText, itemT);
+            }
+            return varValue;
+        }
+    }
+}

+ 61 - 0
ThirdParty/SmartThreadPool/AssemblyInfo.cs

@@ -0,0 +1,61 @@
+using System;
+using System.Reflection;
+using System.Runtime.InteropServices;
+
+//
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]        
+[assembly: ComVisible(false)]
+[assembly: CLSCompliant(true)]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers 
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the 
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing. 
+//
+// Notes: 
+//   (*) If no key is specified, the assembly is not signed.
+//   (*) KeyName refers to a key that has been installed in the Crypto Service
+//       Provider (CSP) on your machine. KeyFile refers to a file which contains
+//       a key.
+//   (*) If the KeyFile and the KeyName values are both specified, the 
+//       following processing occurs:
+//       (1) If the KeyName can be found in the CSP, that key is used.
+//       (2) If the KeyName does not exist and the KeyFile does exist, the key 
+//           in the KeyFile is installed into the CSP and used.
+//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+//       When specifying the KeyFile, the location of the KeyFile should be
+//       relative to the project output directory which is
+//       %Project Directory%\obj\<configuration>. For example, if your KeyFile is
+//       located in the project directory, you would specify the AssemblyKeyFile 
+//       attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+//       documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]

+ 223 - 0
ThirdParty/SmartThreadPool/CallerThreadContext.cs

@@ -0,0 +1,223 @@
+using System;
+using System.Diagnostics;
+using System.Threading;
+using System.Reflection;
+using System.Web;
+using System.Runtime.Remoting.Messaging;
+
+
+namespace Amib.Threading
+{
+    #region CallerThreadContext class
+
+    /// <summary>
+    /// This class stores the caller call context in order to restore
+    /// it when the work item is executed in the thread pool environment. 
+    /// </summary>
+    internal class CallerThreadContext 
+    {
+        #region Prepare reflection information
+
+        // Cached type information.
+        private static MethodInfo getLogicalCallContextMethodInfo =
+            typeof(Thread).GetMethod("GetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
+
+        private static MethodInfo setLogicalCallContextMethodInfo =
+            typeof(Thread).GetMethod("SetLogicalCallContext", BindingFlags.Instance | BindingFlags.NonPublic);
+
+        private static string HttpContextSlotName = GetHttpContextSlotName();
+
+        private static string GetHttpContextSlotName()
+        {
+            FieldInfo fi = typeof(HttpContext).GetField("CallContextSlotName", BindingFlags.Static | BindingFlags.NonPublic);
+
+            if( fi != null )
+                return (string)fi.GetValue(null);
+            else // Use the default "HttpContext" slot name
+                return "HttpContext";
+        }
+
+        #endregion
+
+        #region Private fields
+
+        private HttpContext _httpContext = null;
+        private LogicalCallContext _callContext = null;
+
+        #endregion
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        private CallerThreadContext()
+        {
+        }
+
+        public bool CapturedCallContext
+        {
+            get
+            {
+                return (null != _callContext);
+            }
+        }
+
+        public bool CapturedHttpContext
+        {
+            get
+            {
+                return (null != _httpContext);
+            }
+        }
+
+        /// <summary>
+        /// Captures the current thread context
+        /// </summary>
+        /// <returns></returns>
+        public static CallerThreadContext Capture(
+            bool captureCallContext, 
+            bool captureHttpContext)
+        {
+            Debug.Assert(captureCallContext || captureHttpContext);
+
+            CallerThreadContext callerThreadContext = new CallerThreadContext();
+
+            // TODO: In NET 2.0, redo using the new feature of ExecutionContext class - Capture()
+            // Capture Call Context
+            if(captureCallContext && (getLogicalCallContextMethodInfo != null))
+            {
+                callerThreadContext._callContext = (LogicalCallContext)getLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, null);
+                if (callerThreadContext._callContext != null)
+                {
+                    callerThreadContext._callContext = (LogicalCallContext)callerThreadContext._callContext.Clone();
+                }
+            }
+
+            // Capture httpContext
+            if (captureHttpContext && (null != HttpContext.Current))
+            {
+                callerThreadContext._httpContext = HttpContext.Current;
+            }
+
+            return callerThreadContext;
+        }
+
+        /// <summary>
+        /// Applies the thread context stored earlier
+        /// </summary>
+        /// <param name="callerThreadContext"></param>
+        public static void Apply(CallerThreadContext callerThreadContext)
+        {
+            if (null == callerThreadContext) 
+            {
+                throw new ArgumentNullException("callerThreadContext");            
+            }
+
+            // Todo: In NET 2.0, redo using the new feature of ExecutionContext class - Run()
+            // Restore call context
+            if ((callerThreadContext._callContext != null) && (setLogicalCallContextMethodInfo != null))
+            {
+                setLogicalCallContextMethodInfo.Invoke(Thread.CurrentThread, new object[] { callerThreadContext._callContext });
+            }
+
+            // Restore HttpContext 
+            if (callerThreadContext._httpContext != null)
+            {
+                CallContext.SetData(HttpContextSlotName, callerThreadContext._httpContext);
+            }
+        }
+    }
+
+    #endregion
+
+}
+
+
+/*
+// Ami Bar
+// [email protected]
+
+using System;
+using System.Threading;
+using System.Globalization;
+using System.Security.Principal;
+using System.Reflection;
+using System.Runtime.Remoting.Contexts;
+
+namespace Amib.Threading.Internal
+{
+    #region CallerThreadContext class
+
+    /// <summary>
+    /// This class stores the caller thread context in order to restore
+    /// it when the work item is executed in the context of the thread 
+    /// from the pool.
+    /// Note that we can't store the thread's CompressedStack, because 
+    /// it throws a security exception
+    /// </summary>
+    public class CallerThreadContext
+    {
+        private CultureInfo _culture = null;
+        private CultureInfo _cultureUI = null;
+        private IPrincipal _principal;
+        private System.Runtime.Remoting.Contexts.Context _context;
+
+        private static FieldInfo _fieldInfo = GetFieldInfo();
+
+        private static FieldInfo GetFieldInfo()
+        {
+            Type threadType = typeof(Thread);
+            return threadType.GetField(
+                "m_Context",
+                BindingFlags.Instance | BindingFlags.NonPublic);
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        private CallerThreadContext()
+        {
+        }
+
+        /// <summary>
+        /// Captures the current thread context
+        /// </summary>
+        /// <returns></returns>
+        public static CallerThreadContext Capture()
+        {
+            CallerThreadContext callerThreadContext = new CallerThreadContext();
+
+            Thread thread = Thread.CurrentThread;
+            callerThreadContext._culture = thread.CurrentCulture;
+            callerThreadContext._cultureUI = thread.CurrentUICulture;
+            callerThreadContext._principal = Thread.CurrentPrincipal;
+            callerThreadContext._context = Thread.CurrentContext;
+            return callerThreadContext;
+        }
+
+        /// <summary>
+        /// Applies the thread context stored earlier
+        /// </summary>
+        /// <param name="callerThreadContext"></param>
+        public static void Apply(CallerThreadContext callerThreadContext)
+        {
+            Thread thread = Thread.CurrentThread;
+            thread.CurrentCulture = callerThreadContext._culture;
+            thread.CurrentUICulture = callerThreadContext._cultureUI;
+            Thread.CurrentPrincipal = callerThreadContext._principal;
+
+            // Uncomment the following block to enable the Thread.CurrentThread
+/*
+            if (null != _fieldInfo)
+            {
+                _fieldInfo.SetValue(
+                    Thread.CurrentThread, 
+                    callerThreadContext._context);
+            }
+* /            
+        }
+    }
+
+    #endregion
+}
+*/
+

+ 81 - 0
ThirdParty/SmartThreadPool/Exceptions.cs

@@ -0,0 +1,81 @@
+// Ami Bar
+// [email protected]
+
+using System;
+using System.Runtime.Serialization;
+
+namespace Amib.Threading
+{
+    #region Exceptions
+
+    /// <summary>
+    /// Represents an exception in case IWorkItemResult.GetResult has been canceled
+    /// </summary>
+    [Serializable]
+    public sealed class WorkItemCancelException : ApplicationException
+    {
+        public WorkItemCancelException() : base()
+        {
+        }
+
+        public WorkItemCancelException(string message) : base(message)
+        {
+        }
+
+        public WorkItemCancelException(string message, Exception e) : base(message, e)
+        {
+        }
+
+        public WorkItemCancelException(SerializationInfo si, StreamingContext sc) : base(si, sc)
+        {
+        }
+    }
+
+    /// <summary>
+    /// Represents an exception in case IWorkItemResult.GetResult has been timed out
+    /// </summary>
+    [Serializable]
+    public sealed class WorkItemTimeoutException : ApplicationException
+    {
+        public WorkItemTimeoutException() : base()
+        {
+        }
+
+        public WorkItemTimeoutException(string message) : base(message)
+        {
+        }
+
+        public WorkItemTimeoutException(string message, Exception e) : base(message, e)
+        {
+        }
+
+        public WorkItemTimeoutException(SerializationInfo si, StreamingContext sc) : base(si, sc)
+        {
+        }
+    }
+
+    /// <summary>
+    /// Represents an exception in case IWorkItemResult.GetResult has been timed out
+    /// </summary>
+    [Serializable]
+    public sealed class WorkItemResultException : ApplicationException
+    {
+        public WorkItemResultException() : base()
+        {
+        }
+
+        public WorkItemResultException(string message) : base(message)
+        {
+        }
+
+        public WorkItemResultException(string message, Exception e) : base(message, e)
+        {
+        }
+
+        public WorkItemResultException(SerializationInfo si, StreamingContext sc) : base(si, sc)
+        {
+        }
+    }
+
+    #endregion
+}

+ 271 - 0
ThirdParty/SmartThreadPool/Interfaces.cs

@@ -0,0 +1,271 @@
+// Ami Bar
+// [email protected]
+
+using System;
+using System.Threading;
+
+namespace Amib.Threading
+{
+    #region Delegates
+
+    /// <summary>
+    /// A delegate that represents the method to run as the work item
+    /// </summary>
+    /// <param name="state">A state object for the method to run</param>
+    public delegate object WorkItemCallback(object state);
+
+    /// <summary>
+    /// A delegate to call after the WorkItemCallback completed
+    /// </summary>
+    /// <param name="wir">The work item result object</param>
+    public delegate void PostExecuteWorkItemCallback(IWorkItemResult wir);
+
+    /// <summary>
+    /// A delegate to call when a WorkItemsGroup becomes idle
+    /// </summary>
+    /// <param name="workItemsGroup">A reference to the WorkItemsGroup that became idle</param>
+    public delegate void WorkItemsGroupIdleHandler(IWorkItemsGroup workItemsGroup);
+
+    #endregion
+
+    #region WorkItem Priority
+
+    public enum WorkItemPriority
+    {
+        Lowest,
+        BelowNormal,
+        Normal,
+        AboveNormal,
+        Highest,
+    }
+
+    #endregion
+
+    #region IHasWorkItemPriority interface 
+
+    public interface IHasWorkItemPriority
+    {
+        WorkItemPriority WorkItemPriority { get; }
+    }
+
+    #endregion
+
+    #region IWorkItemsGroup interface 
+
+    /// <summary>
+    /// IWorkItemsGroup interface
+    /// </summary>
+    public interface IWorkItemsGroup
+    {
+        /// <summary>
+        /// Get/Set the name of the WorkItemsGroup
+        /// </summary>
+        string Name { get; set; }
+
+        IWorkItemResult QueueWorkItem(WorkItemCallback callback);
+        IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority);
+        IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state);
+        IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority);
+        IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback);
+        IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, WorkItemPriority workItemPriority);
+        IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute);
+        IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, PostExecuteWorkItemCallback postExecuteWorkItemCallback, CallToPostExecute callToPostExecute, WorkItemPriority workItemPriority);
+
+        IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback);
+        IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state);
+
+        void WaitForIdle();
+        bool WaitForIdle(TimeSpan timeout);
+        bool WaitForIdle(int millisecondsTimeout);
+
+        int WaitingCallbacks { get; }
+        event WorkItemsGroupIdleHandler OnIdle;
+
+        void Cancel();
+        void Start();
+    }
+
+    #endregion
+
+    #region CallToPostExecute enumerator
+
+    [Flags]
+    public enum CallToPostExecute
+    {
+        Never                    = 0x00,
+        WhenWorkItemCanceled     = 0x01,
+        WhenWorkItemNotCanceled  = 0x02,
+        Always                   = WhenWorkItemCanceled | WhenWorkItemNotCanceled,
+    }
+
+    #endregion
+
+    #region IWorkItemResult interface
+
+    /// <summary>
+    /// IWorkItemResult interface
+    /// </summary>
+    public interface IWorkItemResult
+    {
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits.
+        /// </summary>
+        /// <returns>The result of the work item</returns>
+        object GetResult();
+
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits until timeout.
+        /// </summary>
+        /// <returns>The result of the work item</returns>
+        /// On timeout throws WorkItemTimeoutException
+        object GetResult(
+            int millisecondsTimeout,
+            bool exitContext);
+
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits until timeout.
+        /// </summary>
+        /// <returns>The result of the work item</returns>
+        /// On timeout throws WorkItemTimeoutException
+        object GetResult(            
+            TimeSpan timeout,
+            bool exitContext);
+
+        void Abort();
+
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
+        /// </summary>
+        /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
+        /// <returns>The result of the work item</returns>
+        /// On timeout throws WorkItemTimeoutException
+        /// On cancel throws WorkItemCancelException
+        object GetResult(            
+            int millisecondsTimeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle);
+
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
+        /// </summary>
+        /// <returns>The result of the work item</returns>
+        /// On timeout throws WorkItemTimeoutException
+        /// On cancel throws WorkItemCancelException
+        object GetResult(            
+            TimeSpan timeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle);
+
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits.
+        /// </summary>
+        /// <param name="e">Filled with the exception if one was thrown</param>
+        /// <returns>The result of the work item</returns>
+        object GetResult(out Exception e);
+
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits until timeout.
+        /// </summary>
+        /// <param name="e">Filled with the exception if one was thrown</param>
+        /// <returns>The result of the work item</returns>
+        /// On timeout throws WorkItemTimeoutException
+        object GetResult(
+            int millisecondsTimeout,
+            bool exitContext,
+            out Exception e);
+
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits until timeout.
+        /// </summary>
+        /// <param name="e">Filled with the exception if one was thrown</param>
+        /// <returns>The result of the work item</returns>
+        /// On timeout throws WorkItemTimeoutException
+        object GetResult(            
+            TimeSpan timeout,
+            bool exitContext,
+            out Exception e);
+
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
+        /// </summary>
+        /// <param name="millisecondsTimeout">Timeout in milliseconds, or -1 for infinite</param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the blocking if needed</param>
+        /// <param name="e">Filled with the exception if one was thrown</param>
+        /// <returns>The result of the work item</returns>
+        /// On timeout throws WorkItemTimeoutException
+        /// On cancel throws WorkItemCancelException
+        object GetResult(            
+            int millisecondsTimeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle,
+            out Exception e);
+
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits until timeout or until the cancelWaitHandle is signaled.
+        /// </summary>
+        /// <returns>The result of the work item</returns>
+        /// <param name="e">Filled with the exception if one was thrown</param>
+        /// On timeout throws WorkItemTimeoutException
+        /// On cancel throws WorkItemCancelException
+        object GetResult(            
+            TimeSpan timeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle,
+            out Exception e);
+
+        /// <summary>
+        /// Gets an indication whether the asynchronous operation has completed.
+        /// </summary>
+        bool IsCompleted { get; }
+
+        /// <summary>
+        /// Gets an indication whether the asynchronous operation has been canceled.
+        /// </summary>
+        bool IsCanceled { get; }
+
+        /// <summary>
+        /// Gets a user-defined object that qualifies or contains information about an asynchronous operation.
+        /// </summary>
+        object State { get; }
+
+        /// <summary>
+        /// Cancel the work item if it didn't start running yet.
+        /// </summary>
+        /// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
+        bool Cancel();
+
+        /// <summary>
+        /// Get the work item's priority
+        /// </summary>
+        WorkItemPriority WorkItemPriority { get; }
+
+        /// <summary>
+        /// Return the result, same as GetResult()
+        /// </summary>
+        object Result { get; }
+
+        /// <summary>
+        /// Returns the exception if occured otherwise returns null.
+        /// </summary>
+        object Exception { get; }
+    }
+
+    #endregion
+}

+ 240 - 0
ThirdParty/SmartThreadPool/PriorityQueue.cs

@@ -0,0 +1,240 @@
+// Ami Bar
+// [email protected]
+
+using System;
+using System.Collections;
+using System.Diagnostics;
+
+namespace Amib.Threading.Internal
+{
+    #region PriorityQueue class
+
+    /// <summary>
+    /// PriorityQueue class
+    /// This class is not thread safe because we use external lock
+    /// </summary>
+    public sealed class PriorityQueue : IEnumerable
+    {
+        #region Private members
+
+        /// <summary>
+        /// The number of queues, there is one for each type of priority
+        /// </summary>
+        private const int _queuesCount = WorkItemPriority.Highest-WorkItemPriority.Lowest+1;
+
+        /// <summary>
+        /// Work items queues. There is one for each type of priority
+        /// </summary>
+        private Queue [] _queues = new Queue[_queuesCount];
+
+        /// <summary>
+        /// The total number of work items within the queues 
+        /// </summary>
+        private int _workItemsCount = 0;
+
+        /// <summary>
+        /// Use with IEnumerable interface
+        /// </summary>
+        private int _version = 0;
+
+        #endregion
+
+        #region Contructor
+
+        public PriorityQueue()
+        {
+            for(int i = 0; i < _queues.Length; ++i)
+            {
+                _queues[i] = new Queue();
+            }
+        }
+
+        #endregion
+
+        #region Methods
+
+        /// <summary>
+        /// Enqueue a work item.
+        /// </summary>
+        /// <param name="workItem">A work item</param>
+        public void Enqueue(IHasWorkItemPriority workItem)
+        {
+            Debug.Assert(null != workItem);
+
+            int queueIndex = _queuesCount-(int)workItem.WorkItemPriority-1;
+            Debug.Assert(queueIndex >= 0);
+            Debug.Assert(queueIndex < _queuesCount);
+
+            _queues[queueIndex].Enqueue(workItem);
+            ++_workItemsCount;
+            ++_version;
+        }
+
+        /// <summary>
+        /// Dequeque a work item.
+        /// </summary>
+        /// <returns>Returns the next work item</returns>
+        public IHasWorkItemPriority Dequeue()
+        {
+            IHasWorkItemPriority workItem = null;
+
+            if(_workItemsCount > 0)
+            {
+                int queueIndex = GetNextNonEmptyQueue(-1);
+                Debug.Assert(queueIndex >= 0);
+                workItem = _queues[queueIndex].Dequeue() as IHasWorkItemPriority;
+                Debug.Assert(null != workItem);
+                --_workItemsCount;
+                ++_version;
+            }
+
+            return workItem;
+        }
+
+        /// <summary>
+        /// Find the next non empty queue starting at queue queueIndex+1
+        /// </summary>
+        /// <param name="queueIndex">The index-1 to start from</param>
+        /// <returns>
+        /// The index of the next non empty queue or -1 if all the queues are empty
+        /// </returns>
+        private int GetNextNonEmptyQueue(int queueIndex)
+        {
+            for(int i = queueIndex+1; i < _queuesCount; ++i)
+            {
+                if(_queues[i].Count > 0)
+                {
+                    return i;
+                }
+            }
+            return -1;
+        }
+
+        /// <summary>
+        /// The number of work items 
+        /// </summary>
+        public int Count
+        {
+            get
+            {
+                return _workItemsCount;
+            }
+        }
+
+        /// <summary>
+        /// Clear all the work items 
+        /// </summary>
+        public void Clear()
+        {
+            if (_workItemsCount > 0)
+            {
+                foreach(Queue queue in _queues)
+                {
+                    queue.Clear();
+                }
+                _workItemsCount = 0;
+                ++_version;
+            }
+        }
+
+        #endregion
+
+        #region IEnumerable Members
+
+        /// <summary>
+        /// Returns an enumerator to iterate over the work items
+        /// </summary>
+        /// <returns>Returns an enumerator</returns>
+        public IEnumerator GetEnumerator()
+        {
+            return new PriorityQueueEnumerator(this);
+        }
+
+        #endregion
+
+        #region PriorityQueueEnumerator
+
+        /// <summary>
+        /// The class the implements the enumerator
+        /// </summary>
+        private class PriorityQueueEnumerator : IEnumerator
+        {
+            private PriorityQueue _priorityQueue;
+            private int _version;
+            private int _queueIndex;
+            private IEnumerator _enumerator;
+
+            public PriorityQueueEnumerator(PriorityQueue priorityQueue)
+            {
+                _priorityQueue = priorityQueue;
+                _version = _priorityQueue._version;
+                _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
+                if (_queueIndex >= 0)
+                {
+                    _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
+                }
+                else
+                {
+                    _enumerator = null;
+                }
+            }
+
+            #region IEnumerator Members
+
+            public void Reset()
+            {
+                _version = _priorityQueue._version;
+                _queueIndex = _priorityQueue.GetNextNonEmptyQueue(-1);
+                if (_queueIndex >= 0)
+                {
+                    _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
+                }
+                else
+                {
+                    _enumerator = null;
+                }
+            }
+
+            public object Current
+            {
+                get
+                {
+                    Debug.Assert(null != _enumerator);
+                    return _enumerator.Current;
+                }
+            }
+
+            public bool MoveNext()
+            {
+                if (null == _enumerator)
+                {
+                    return false;
+                }
+
+                if(_version != _priorityQueue._version)
+                {
+                    throw new InvalidOperationException("The collection has been modified");
+
+                }
+                if (!_enumerator.MoveNext())
+                {
+                    _queueIndex = _priorityQueue.GetNextNonEmptyQueue(_queueIndex);
+                    if(-1 == _queueIndex)
+                    {
+                        return false;
+                    }
+                    _enumerator = _priorityQueue._queues[_queueIndex].GetEnumerator();
+                    _enumerator.MoveNext();
+                    return true;
+                }
+                return true;
+            }
+
+            #endregion
+        }
+
+        #endregion
+    }
+
+    #endregion
+}

+ 352 - 0
ThirdParty/SmartThreadPool/STPPerformanceCounter.cs

@@ -0,0 +1,352 @@
+using System;
+using System.Diagnostics;
+
+namespace Amib.Threading.Internal
+{
+    internal enum STPPerformanceCounterType
+    {
+        // Fields
+        ActiveThreads                = 0,
+        InUseThreads                = 1,
+        OverheadThreads                = 2,
+        OverheadThreadsPercent        = 3,
+        OverheadThreadsPercentBase    = 4,
+
+        WorkItems                    = 5,
+        WorkItemsInQueue            = 6,
+        WorkItemsProcessed            = 7,
+
+        WorkItemsQueuedPerSecond    = 8,
+        WorkItemsProcessedPerSecond    = 9,
+
+        AvgWorkItemWaitTime            = 10,
+        AvgWorkItemWaitTimeBase        = 11,
+
+        AvgWorkItemProcessTime        = 12,
+        AvgWorkItemProcessTimeBase    = 13,
+
+        WorkItemsGroups                = 14,
+
+        LastCounter                    = 14,
+    }
+ 
+
+    /// <summary>
+    /// Summary description for STPPerformanceCounter.
+    /// </summary>
+    internal class STPPerformanceCounter
+    {
+        // Fields
+        private PerformanceCounterType _pcType;
+        protected string _counterHelp;
+        protected string _counterName;
+
+        // Methods
+        public STPPerformanceCounter(
+            string counterName, 
+            string counterHelp, 
+            PerformanceCounterType pcType)
+        {
+            this._counterName = counterName;
+            this._counterHelp = counterHelp;
+            this._pcType = pcType;
+        }
+
+        public void AddCounterToCollection(CounterCreationDataCollection counterData)
+        {
+            CounterCreationData counterCreationData = new CounterCreationData(
+                _counterName, 
+                _counterHelp, 
+                _pcType);
+
+            counterData.Add(counterCreationData);
+        }
+ 
+        // Properties
+        public string Name
+        {
+            get
+            {
+                return _counterName;
+            }
+        }
+    }
+
+    internal class STPPerformanceCounters
+    {
+        // Fields
+        internal STPPerformanceCounter[] _stpPerformanceCounters;
+        private static STPPerformanceCounters _instance;
+        internal const string _stpCategoryHelp = "SmartThreadPool performance counters";
+        internal const string _stpCategoryName = "SmartThreadPool";
+
+        // Methods
+        static STPPerformanceCounters()
+        {
+            _instance = new STPPerformanceCounters();
+        }
+ 
+        private STPPerformanceCounters()
+        {
+            STPPerformanceCounter[] stpPerformanceCounters = new STPPerformanceCounter[] 
+                { 
+                    new STPPerformanceCounter("Active threads", "The current number of available in the thread pool.", PerformanceCounterType.NumberOfItems32), 
+                    new STPPerformanceCounter("In use threads", "The current number of threads that execute a work item.", PerformanceCounterType.NumberOfItems32), 
+                    new STPPerformanceCounter("Overhead threads", "The current number of threads that are active, but are not in use.", PerformanceCounterType.NumberOfItems32), 
+                    new STPPerformanceCounter("% overhead threads", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawFraction), 
+                    new STPPerformanceCounter("% overhead threads base", "The current number of threads that are active, but are not in use in percents.", PerformanceCounterType.RawBase), 
+
+                    new STPPerformanceCounter("Work Items", "The number of work items in the Smart Thread Pool. Both queued and processed.", PerformanceCounterType.NumberOfItems32), 
+                    new STPPerformanceCounter("Work Items in queue", "The current number of work items in the queue", PerformanceCounterType.NumberOfItems32), 
+                    new STPPerformanceCounter("Work Items processed", "The number of work items already processed", PerformanceCounterType.NumberOfItems32), 
+
+                    new STPPerformanceCounter("Work Items queued/sec", "The number of work items queued per second", PerformanceCounterType.RateOfCountsPerSecond32), 
+                    new STPPerformanceCounter("Work Items processed/sec", "The number of work items processed per second", PerformanceCounterType.RateOfCountsPerSecond32), 
+
+                    new STPPerformanceCounter("Avg. Work Item wait time/sec", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageCount64), 
+                    new STPPerformanceCounter("Avg. Work Item wait time base", "The average time a work item supends in the queue waiting for its turn to execute.", PerformanceCounterType.AverageBase), 
+
+                    new STPPerformanceCounter("Avg. Work Item process time/sec", "The average time it takes to process a work item.", PerformanceCounterType.AverageCount64), 
+                    new STPPerformanceCounter("Avg. Work Item process time base", "The average time it takes to process a work item.", PerformanceCounterType.AverageBase), 
+
+                    new STPPerformanceCounter("Work Items Groups", "The current number of work item groups associated with the Smart Thread Pool.", PerformanceCounterType.NumberOfItems32), 
+                };
+
+            _stpPerformanceCounters = stpPerformanceCounters;
+            SetupCategory();
+        }
+ 
+        private void SetupCategory()
+        {
+            if (!PerformanceCounterCategory.Exists(_stpCategoryName))
+            {
+                CounterCreationDataCollection counters = new CounterCreationDataCollection();
+
+                for (int i = 0; i < _stpPerformanceCounters.Length; i++)
+                {
+                    _stpPerformanceCounters[i].AddCounterToCollection(counters);
+                }
+
+
+                // *********** Remark for .NET 2.0 ***********
+                // If you are here, it means you got the warning that this overload
+                // of the method is deprecated in .NET 2.0. To use the correct 
+                // method overload, uncomment the third argument of the method.
+                PerformanceCounterCategory.Create(
+                    _stpCategoryName, 
+                    _stpCategoryHelp, 
+                    //PerformanceCounterCategoryType.MultiInstance,
+                    counters);
+                    
+            }
+        }
+ 
+        // Properties
+        public static STPPerformanceCounters Instance
+        {
+            get
+            {
+                return _instance;
+            }
+        }
+     }
+
+    internal class STPInstancePerformanceCounter : IDisposable
+    {
+        // Fields
+        private PerformanceCounter _pcs;
+
+        // Methods
+        protected STPInstancePerformanceCounter()
+        {
+        }
+
+        public STPInstancePerformanceCounter(
+            string instance, 
+            STPPerformanceCounterType spcType)
+        {
+            STPPerformanceCounters counters = STPPerformanceCounters.Instance;
+            _pcs = new PerformanceCounter(
+                STPPerformanceCounters._stpCategoryName, 
+                counters._stpPerformanceCounters[(int) spcType].Name, 
+                instance, 
+                false);
+            _pcs.RawValue = _pcs.RawValue;
+        }
+
+        ~STPInstancePerformanceCounter()
+        {
+            Close();
+        }
+
+        public void Close()
+        {
+            if (_pcs != null)
+            {
+                _pcs.RemoveInstance();
+                _pcs.Close();
+                _pcs = null;
+            }
+        }
+ 
+        public void Dispose()
+        {
+            Close();
+            GC.SuppressFinalize(this);
+        }
+ 
+        public virtual void Increment()
+        {
+            _pcs.Increment();
+        }
+ 
+        public virtual void IncrementBy(long val)
+        {
+            _pcs.IncrementBy(val);
+        }
+
+        public virtual void Set(long val)
+        {
+            _pcs.RawValue = val;
+        }
+    }
+
+    internal class STPInstanceNullPerformanceCounter : STPInstancePerformanceCounter
+    {
+        // Methods
+        public STPInstanceNullPerformanceCounter() {}
+        public override void Increment() {}
+        public override void IncrementBy(long value) {}
+        public override void Set(long val) {}
+    }
+        
+    internal interface ISTPInstancePerformanceCounters : IDisposable
+    {
+        void Close();
+        void SampleThreads(long activeThreads, long inUseThreads);
+        void SampleWorkItems(long workItemsQueued, long workItemsProcessed);
+        void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime);
+        void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime);
+    }
+
+
+    internal class STPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable
+    {
+        // Fields
+        private STPInstancePerformanceCounter[] _pcs;
+        private static STPInstancePerformanceCounter _stpInstanceNullPerformanceCounter;
+
+        // Methods
+        static STPInstancePerformanceCounters()
+        {
+            _stpInstanceNullPerformanceCounter = new STPInstanceNullPerformanceCounter();
+        }
+ 
+        public STPInstancePerformanceCounters(string instance)
+        {
+            _pcs = new STPInstancePerformanceCounter[(int)STPPerformanceCounterType.LastCounter];
+            STPPerformanceCounters counters = STPPerformanceCounters.Instance;
+            for (int i = 0; i < _pcs.Length; i++)
+            {
+                if (instance != null)
+                {
+                    _pcs[i] = new STPInstancePerformanceCounter(
+                        instance, 
+                        (STPPerformanceCounterType) i);
+                }
+                else
+                {
+                    _pcs[i] = _stpInstanceNullPerformanceCounter;
+                }
+            }
+        }
+ 
+
+        public void Close()
+        {
+            if (null != _pcs)
+            {
+                for (int i = 0; i < _pcs.Length; i++)
+                {
+                    if (null != _pcs[i])
+                    {
+                        _pcs[i].Close();
+                    }
+                }
+                _pcs = null;
+            }
+        }
+
+        ~STPInstancePerformanceCounters()
+        {
+            Close();
+        }
+
+        public void Dispose()
+        {
+            Close();
+            GC.SuppressFinalize(this);
+        }
+ 
+        private STPInstancePerformanceCounter GetCounter(STPPerformanceCounterType spcType)
+        {
+            return _pcs[(int) spcType];
+        }
+
+        public void SampleThreads(long activeThreads, long inUseThreads)
+        {
+            GetCounter(STPPerformanceCounterType.ActiveThreads).Set(activeThreads);
+            GetCounter(STPPerformanceCounterType.InUseThreads).Set(inUseThreads);
+            GetCounter(STPPerformanceCounterType.OverheadThreads).Set(activeThreads-inUseThreads);
+
+            GetCounter(STPPerformanceCounterType.OverheadThreadsPercentBase).Set(activeThreads-inUseThreads);
+            GetCounter(STPPerformanceCounterType.OverheadThreadsPercent).Set(inUseThreads);
+        }
+
+        public void SampleWorkItems(long workItemsQueued, long workItemsProcessed)
+        {
+            GetCounter(STPPerformanceCounterType.WorkItems).Set(workItemsQueued+workItemsProcessed);
+            GetCounter(STPPerformanceCounterType.WorkItemsInQueue).Set(workItemsQueued);
+            GetCounter(STPPerformanceCounterType.WorkItemsProcessed).Set(workItemsProcessed);
+
+            GetCounter(STPPerformanceCounterType.WorkItemsQueuedPerSecond).Set(workItemsQueued);
+            GetCounter(STPPerformanceCounterType.WorkItemsProcessedPerSecond).Set(workItemsProcessed);
+        }
+
+        public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime)
+        {
+            GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTime).IncrementBy((long)workItemWaitTime.TotalMilliseconds);
+            GetCounter(STPPerformanceCounterType.AvgWorkItemWaitTimeBase).Increment();
+        }
+
+        public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime)
+        {
+            GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTime).IncrementBy((long)workItemProcessTime.TotalMilliseconds);
+            GetCounter(STPPerformanceCounterType.AvgWorkItemProcessTimeBase).Increment();
+        }
+    }
+
+    internal class NullSTPInstancePerformanceCounters : ISTPInstancePerformanceCounters, IDisposable
+    {
+        static NullSTPInstancePerformanceCounters()
+        {
+        }
+
+        private static NullSTPInstancePerformanceCounters _instance = new NullSTPInstancePerformanceCounters(null);
+
+        public static NullSTPInstancePerformanceCounters Instance
+        {
+            get { return _instance; }
+        }
+
+        public NullSTPInstancePerformanceCounters(string instance) {}
+         public void Close() {}
+        public void Dispose() {}
+ 
+        public void SampleThreads(long activeThreads, long inUseThreads) {}
+        public void SampleWorkItems(long workItemsQueued, long workItemsProcessed) {}
+        public void SampleWorkItemsWaitTime(TimeSpan workItemWaitTime) {}
+        public void SampleWorkItemsProcessTime(TimeSpan workItemProcessTime) {}
+    }
+
+}

+ 99 - 0
ThirdParty/SmartThreadPool/STPStartInfo.cs

@@ -0,0 +1,99 @@
+// Ami Bar
+// [email protected]
+
+using System.Threading;
+
+namespace Amib.Threading
+{
+    /// <summary>
+    /// Summary description for STPStartInfo.
+    /// </summary>
+    public class STPStartInfo : WIGStartInfo
+    {
+        /// <summary>
+        /// Idle timeout in milliseconds.
+        /// If a thread is idle for _idleTimeout milliseconds then 
+        /// it may quit.
+        /// </summary>
+        private int _idleTimeout;
+
+        /// <summary>
+        /// The lower limit of threads in the pool.
+        /// </summary>
+        private int _minWorkerThreads;
+
+        /// <summary>
+        /// The upper limit of threads in the pool.
+        /// </summary>
+        private int _maxWorkerThreads;
+
+        /// <summary>
+        /// The priority of the threads in the pool
+        /// </summary>
+        private ThreadPriority _threadPriority;
+
+        /// <summary>
+        /// If this field is not null then the performance counters are enabled
+        /// and use the string as the name of the instance.
+        /// </summary>
+        private string _pcInstanceName;
+
+        private int _stackSize;
+
+        public STPStartInfo() : base()
+        {
+            _idleTimeout = SmartThreadPool.DefaultIdleTimeout;
+            _minWorkerThreads = SmartThreadPool.DefaultMinWorkerThreads;
+            _maxWorkerThreads = SmartThreadPool.DefaultMaxWorkerThreads;
+            _threadPriority = SmartThreadPool.DefaultThreadPriority;
+            _pcInstanceName = SmartThreadPool.DefaultPerformanceCounterInstanceName;
+            _stackSize = SmartThreadPool.DefaultStackSize;
+        }
+
+        public STPStartInfo(STPStartInfo stpStartInfo) : base(stpStartInfo)
+        {
+            _idleTimeout = stpStartInfo._idleTimeout;
+            _minWorkerThreads = stpStartInfo._minWorkerThreads;
+            _maxWorkerThreads = stpStartInfo._maxWorkerThreads;
+            _threadPriority = stpStartInfo._threadPriority;
+            _pcInstanceName = stpStartInfo._pcInstanceName;
+            _stackSize = stpStartInfo._stackSize;
+        }
+
+        public int IdleTimeout
+        {
+            get { return _idleTimeout; }
+            set { _idleTimeout = value; }
+        }
+
+        public int MinWorkerThreads
+        {
+            get { return _minWorkerThreads; }
+            set { _minWorkerThreads = value; }
+        }
+
+        public int MaxWorkerThreads
+        {
+            get { return _maxWorkerThreads; }
+            set { _maxWorkerThreads = value; }
+        }
+
+        public ThreadPriority ThreadPriority
+        {
+            get { return _threadPriority; }
+            set { _threadPriority = value; }
+        }
+
+        public string PerformanceCounterInstanceName
+        {
+            get { return _pcInstanceName; }
+            set { _pcInstanceName = value; }
+        }
+
+        public int StackSize
+        {
+            get { return _stackSize; }
+            set { _stackSize = value; }
+        }
+    }
+}

+ 1438 - 0
ThirdParty/SmartThreadPool/SmartThreadPool.cs

@@ -0,0 +1,1438 @@
+// Ami Bar
+// [email protected]
+//
+// Smart thread pool in C#.
+// 7 Aug 2004 - Initial release
+// 14 Sep 2004 - Bug fixes 
+// 15 Oct 2004 - Added new features
+//        - Work items return result.
+//        - Support waiting synchronization for multiple work items.
+//        - Work items can be cancelled.
+//        - Passage of the caller thread’s context to the thread in the pool.
+//        - Minimal usage of WIN32 handles.
+//        - Minor bug fixes.
+// 26 Dec 2004 - Changes:
+//        - Removed static constructors.
+//      - Added finalizers.
+//        - Changed Exceptions so they are serializable.
+//        - Fixed the bug in one of the SmartThreadPool constructors.
+//        - Changed the SmartThreadPool.WaitAll() so it will support any number of waiters. 
+//        The SmartThreadPool.WaitAny() is still limited by the .NET Framework.
+//        - Added PostExecute with options on which cases to call it.
+//      - Added option to dispose of the state objects.
+//      - Added a WaitForIdle() method that waits until the work items queue is empty.
+//      - Added an STPStartInfo class for the initialization of the thread pool.
+//      - Changed exception handling so if a work item throws an exception it 
+//        is rethrown at GetResult(), rather then firing an UnhandledException event.
+//        Note that PostExecute exception are always ignored.
+// 25 Mar 2005 - Changes:
+//        - Fixed lost of work items bug
+// 3 Jul 2005: Changes.
+//      - Fixed bug where Enqueue() throws an exception because PopWaiter() returned null, hardly reconstructed. 
+// 16 Aug 2005: Changes.
+//        - Fixed bug where the InUseThreads becomes negative when canceling work items. 
+//
+// 31 Jan 2006 - Changes:
+//        - Added work items priority
+//        - Removed support of chained delegates in callbacks and post executes (nobody really use this)
+//        - Added work items groups
+//        - Added work items groups idle event
+//        - Changed SmartThreadPool.WaitAll() behavior so when it gets empty array
+//          it returns true rather then throwing an exception.
+//        - Added option to start the STP and the WIG as suspended
+//        - Exception behavior changed, the real exception is returned by an 
+//          inner exception
+//        - Added option to keep the Http context of the caller thread. (Thanks to Steven T.)
+//        - Added performance counters
+//        - Added priority to the threads in the pool
+//
+// 13 Feb 2006 - Changes:
+//        - Added a call to the dispose of the Performance Counter so
+//          their won't be a Performance Counter leak.
+//        - Added exception catch in case the Performance Counters cannot 
+//          be created.
+
+using System;
+using System.Security;
+using System.Threading;
+using System.Collections;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+using Amib.Threading.Internal;
+
+namespace Amib.Threading
+{
+    #region SmartThreadPool class
+    /// <summary>
+    /// Smart thread pool class.
+    /// </summary>
+    public class SmartThreadPool : IWorkItemsGroup, IDisposable
+    {
+        #region Default Constants
+
+        /// <summary>
+        /// Default minimum number of threads the thread pool contains. (0)
+        /// </summary>
+        public const int DefaultMinWorkerThreads = 0;
+
+        /// <summary>
+        /// Default maximum number of threads the thread pool contains. (25)
+        /// </summary>
+        public const int DefaultMaxWorkerThreads = 25;
+
+        /// <summary>
+        /// Default idle timeout in milliseconds. (One minute)
+        /// </summary>
+        public const int DefaultIdleTimeout = 60*1000; // One minute
+
+        /// <summary>
+        /// Indicate to copy the security context of the caller and then use it in the call. (false)
+        /// </summary>
+        public const bool DefaultUseCallerCallContext = false; 
+
+        /// <summary>
+        /// Indicate to copy the HTTP context of the caller and then use it in the call. (false)
+        /// </summary>
+        public const bool DefaultUseCallerHttpContext = false;
+
+        /// <summary>
+        /// Indicate to dispose of the state objects if they support the IDispose interface. (false)
+        /// </summary>
+        public const bool DefaultDisposeOfStateObjects = false; 
+
+        /// <summary>
+        /// The default option to run the post execute
+        /// </summary>
+        public const CallToPostExecute DefaultCallToPostExecute = CallToPostExecute.Always;
+
+        /// <summary>
+        /// The default post execute method to run. 
+        /// When null it means not to call it.
+        /// </summary>
+        public static readonly PostExecuteWorkItemCallback DefaultPostExecuteWorkItemCallback = null;
+
+        /// <summary>
+        /// The default work item priority
+        /// </summary>
+        public const WorkItemPriority DefaultWorkItemPriority = WorkItemPriority.Normal;
+
+        /// <summary>
+        /// The default is to work on work items as soon as they arrive
+        /// and not to wait for the start.
+        /// </summary>
+        public const bool DefaultStartSuspended = false;
+
+        /// <summary>
+        /// The default is not to use the performance counters
+        /// </summary>
+        public static readonly string DefaultPerformanceCounterInstanceName = null;
+
+        public static readonly int DefaultStackSize = 0;
+
+        /// <summary>
+        /// The default thread priority
+        /// </summary>
+        public const ThreadPriority DefaultThreadPriority = ThreadPriority.Normal;
+
+        #endregion
+
+        #region Member Variables
+
+        /// <summary>
+        /// Contains the name of this instance of SmartThreadPool.
+        /// Can be changed by the user.
+        /// </summary>
+        private string _name = "SmartThreadPool";
+
+        /// <summary>
+        /// Hashtable of all the threads in the thread pool.
+        /// </summary>
+        private Hashtable _workerThreads = Hashtable.Synchronized(new Hashtable());
+
+        /// <summary>
+        /// Queue of work items.
+        /// </summary>
+        private WorkItemsQueue _workItemsQueue = new WorkItemsQueue();
+
+        /// <summary>
+        /// Count the work items handled.
+        /// Used by the performance counter.
+        /// </summary>
+        private long _workItemsProcessed = 0;
+
+        /// <summary>
+        /// Number of threads that currently work (not idle).
+        /// </summary>
+        private int _inUseWorkerThreads = 0;
+
+        /// <summary>
+        /// Start information to use. 
+        /// It is simpler than providing many constructors.
+        /// </summary>
+        private STPStartInfo _stpStartInfo = new STPStartInfo();
+
+        /// <summary>
+        /// Total number of work items that are stored in the work items queue 
+        /// plus the work items that the threads in the pool are working on.
+        /// </summary>
+        private int _currentWorkItemsCount = 0;
+
+        /// <summary>
+        /// Signaled when the thread pool is idle, i.e. no thread is busy
+        /// and the work items queue is empty
+        /// </summary>
+        private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
+
+        /// <summary>
+        /// An event to signal all the threads to quit immediately.
+        /// </summary>
+        private ManualResetEvent _shuttingDownEvent = new ManualResetEvent(false);
+
+        /// <summary>
+        /// A flag to indicate the threads to quit.
+        /// </summary>
+        private bool _shutdown = false;
+
+        /// <summary>
+        /// Counts the threads created in the pool.
+        /// It is used to name the threads.
+        /// </summary>
+        private int _threadCounter = 0;
+
+        /// <summary>
+        /// Indicate that the SmartThreadPool has been disposed
+        /// </summary>
+        private bool _isDisposed = false;
+
+        /// <summary>
+        /// Event to send that the thread pool is idle
+        /// </summary>
+        private event EventHandler _stpIdle;
+
+        /// <summary>
+        /// On idle event
+        /// </summary>
+        //private event WorkItemsGroupIdleHandler _onIdle;
+
+        /// <summary>
+        /// Holds all the WorkItemsGroup instaces that have at least one 
+        /// work item int the SmartThreadPool
+        /// This variable is used in case of Shutdown
+        /// </summary>
+        private Hashtable _workItemsGroups = Hashtable.Synchronized(new Hashtable());
+
+        /// <summary>
+        /// A reference from each thread in the thread pool to its SmartThreadPool
+        /// object container.
+        /// With this variable a thread can know whatever it belongs to a 
+        /// SmartThreadPool.
+        /// </summary>
+        [ThreadStatic]
+        private static SmartThreadPool _smartThreadPool;
+
+        /// <summary>
+        /// A reference to the current work item a thread from the thread pool 
+        /// is executing.
+        /// </summary>
+        [ThreadStatic]
+        private static WorkItem _currentWorkItem;
+
+        /// <summary>
+        /// STP performance counters
+        /// </summary>
+        private ISTPInstancePerformanceCounters _pcs = NullSTPInstancePerformanceCounters.Instance;
+
+        #endregion
+
+        #region Construction and Finalization
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public SmartThreadPool()
+        {
+            Initialize();
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="idleTimeout">Idle timeout in milliseconds</param>
+        public SmartThreadPool(int idleTimeout)
+        {
+            _stpStartInfo.IdleTimeout = idleTimeout;
+            Initialize();
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="idleTimeout">Idle timeout in milliseconds</param>
+        /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param>
+        public SmartThreadPool(
+            int idleTimeout,
+            int maxWorkerThreads)
+        {
+            _stpStartInfo.IdleTimeout = idleTimeout;
+            _stpStartInfo.MaxWorkerThreads = maxWorkerThreads;
+            Initialize();
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        /// <param name="idleTimeout">Idle timeout in milliseconds</param>
+        /// <param name="maxWorkerThreads">Upper limit of threads in the pool</param>
+        /// <param name="minWorkerThreads">Lower limit of threads in the pool</param>
+        public SmartThreadPool(
+            int idleTimeout,
+            int maxWorkerThreads,
+            int minWorkerThreads)
+        {
+            _stpStartInfo.IdleTimeout = idleTimeout;
+            _stpStartInfo.MaxWorkerThreads = maxWorkerThreads;
+            _stpStartInfo.MinWorkerThreads = minWorkerThreads;
+            Initialize();
+        }
+
+        /// <summary>
+        /// Constructor
+        /// </summary>
+        public SmartThreadPool(STPStartInfo stpStartInfo)
+        {
+            _stpStartInfo = new STPStartInfo(stpStartInfo);
+            Initialize();
+        }
+
+        private void Initialize()
+        {
+            ValidateSTPStartInfo();
+
+            if (null != _stpStartInfo.PerformanceCounterInstanceName)
+            {
+                try
+                {
+                    _pcs = new STPInstancePerformanceCounters(_stpStartInfo.PerformanceCounterInstanceName);
+                }
+                catch(Exception e)
+                {
+                    Debug.WriteLine("Unable to create Performance Counters: " + e.ToString());
+                    _pcs = NullSTPInstancePerformanceCounters.Instance;
+                }
+            }
+
+            StartOptimalNumberOfThreads();
+        }
+
+        private void StartOptimalNumberOfThreads()
+        {
+            int threadsCount = Math.Max(_workItemsQueue.Count, _stpStartInfo.MinWorkerThreads);
+            threadsCount = Math.Min(threadsCount, _stpStartInfo.MaxWorkerThreads);
+            StartThreads(threadsCount);
+        }
+
+        private void ValidateSTPStartInfo()
+        {
+            if (_stpStartInfo.MinWorkerThreads < 0)
+            {
+                throw new ArgumentOutOfRangeException(
+                    "MinWorkerThreads", "MinWorkerThreads cannot be negative");
+            }
+
+            if (_stpStartInfo.MaxWorkerThreads <= 0)
+            {
+                throw new ArgumentOutOfRangeException(
+                    "MaxWorkerThreads", "MaxWorkerThreads must be greater than zero");
+            }
+
+            if (_stpStartInfo.MinWorkerThreads > _stpStartInfo.MaxWorkerThreads)
+            {
+                throw new ArgumentOutOfRangeException(
+                    "MinWorkerThreads, maxWorkerThreads", 
+                    "MaxWorkerThreads must be greater or equal to MinWorkerThreads");
+            }
+        }
+
+        private void ValidateCallback(Delegate callback)
+        {
+            if(callback.GetInvocationList().Length > 1)
+            {
+                throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
+            }
+        }
+
+        #endregion
+
+        #region Thread Processing
+
+        /// <summary>
+        /// Waits on the queue for a work item, shutdown, or timeout.
+        /// </summary>
+        /// <returns>
+        /// Returns the WaitingCallback or null in case of timeout or shutdown.
+        /// </returns>
+        private WorkItem Dequeue()
+        {
+            WorkItem workItem = 
+                _workItemsQueue.DequeueWorkItem(_stpStartInfo.IdleTimeout, _shuttingDownEvent);
+
+            return workItem;
+        }
+
+        /// <summary>
+        /// Put a new work item in the queue
+        /// </summary>
+        /// <param name="workItem">A work item to queue</param>
+        private void Enqueue(WorkItem workItem)
+        {
+            Enqueue(workItem, true);
+        }
+
+        /// <summary>
+        /// Put a new work item in the queue
+        /// </summary>
+        /// <param name="workItem">A work item to queue</param>
+        internal void Enqueue(WorkItem workItem, bool incrementWorkItems)
+        {
+            // Make sure the workItem is not null
+            Debug.Assert(null != workItem);
+
+            if (incrementWorkItems)
+            {
+                IncrementWorkItemsCount();
+            }
+
+            _workItemsQueue.EnqueueWorkItem(workItem);
+            workItem.WorkItemIsQueued();
+
+            // If all the threads are busy then try to create a new one
+            if ((InUseThreads + WaitingCallbacks) > _workerThreads.Count) 
+            {
+                StartThreads(1);
+            }
+        }
+
+        private void IncrementWorkItemsCount()
+        {
+            _pcs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
+
+            int count = Interlocked.Increment(ref _currentWorkItemsCount);
+            //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString());
+            if (count == 1) 
+            {
+                //Trace.WriteLine("STP is NOT idle");
+                _isIdleWaitHandle.Reset();
+            }
+        }
+
+        private void DecrementWorkItemsCount()
+        {
+            ++_workItemsProcessed;
+
+            // The counter counts even if the work item was cancelled
+            _pcs.SampleWorkItems(_workItemsQueue.Count, _workItemsProcessed);
+
+            int count = Interlocked.Decrement(ref _currentWorkItemsCount);
+            //Trace.WriteLine("WorkItemsCount = " + _currentWorkItemsCount.ToString());
+            if (count == 0) 
+            {
+                //Trace.WriteLine("STP is idle");
+                _isIdleWaitHandle.Set();
+            }
+        }
+
+        internal void RegisterWorkItemsGroup(IWorkItemsGroup workItemsGroup)
+        {
+            _workItemsGroups[workItemsGroup] = workItemsGroup;
+        }
+
+        internal void UnregisterWorkItemsGroup(IWorkItemsGroup workItemsGroup)
+        {
+            if (_workItemsGroups.Contains(workItemsGroup))
+            {
+                _workItemsGroups.Remove(workItemsGroup);
+            }
+        }
+
+        /// <summary>
+        /// Inform that the current thread is about to quit or quiting.
+        /// The same thread may call this method more than once.
+        /// </summary>
+        private void InformCompleted()
+        {
+            // There is no need to lock the two methods together 
+            // since only the current thread removes itself
+            // and the _workerThreads is a synchronized hashtable
+            if (_workerThreads.Contains(Thread.CurrentThread))
+            {
+                _workerThreads.Remove(Thread.CurrentThread);
+                _pcs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
+            }
+        }
+
+        /// <summary>
+        /// Starts new threads
+        /// </summary>
+        /// <param name="threadsCount">The number of threads to start</param>
+        private void StartThreads(int threadsCount)
+        {
+            if (_stpStartInfo.StartSuspended)
+            {
+                return;
+            }
+
+            lock(_workerThreads.SyncRoot)
+            {
+                // Don't start threads on shut down
+                if (_shutdown)
+                {
+                    return;
+                }
+
+                for(int i = 0; i < threadsCount; ++i)
+                {
+                    // Don't create more threads then the upper limit
+                    if (_workerThreads.Count >= _stpStartInfo.MaxWorkerThreads)
+                    {
+                        return;
+                    }
+
+                    // Create a new thread
+                    Thread workerThread = new Thread(new ThreadStart(ProcessQueuedItems), _stpStartInfo.StackSize);
+
+                    // Configure the new thread and start it
+                    workerThread.Name = "STP " + Name + " Thread #" + _threadCounter;
+                    workerThread.IsBackground = true;
+                    workerThread.Priority = _stpStartInfo.ThreadPriority;
+                    workerThread.Start();
+                    ++_threadCounter;
+
+                    // Add the new thread to the hashtable and update its creation
+                    // time.
+                    _workerThreads[workerThread] = DateTime.Now;
+                    _pcs.SampleThreads(_workerThreads.Count, _inUseWorkerThreads);
+                }
+            }
+        }
+
+        /// <summary>
+        /// A worker thread method that processes work items from the work items queue.
+        /// </summary>
+        private void ProcessQueuedItems()
+        {
+            // Initialize the _smartThreadPool variable
+            _smartThreadPool = this;
+
+            try
+            {
+                bool bInUseWorkerThreadsWasIncremented = false;
+
+                // Process until shutdown.
+                while(!_shutdown)
+                {
+                    // Update the last time this thread was seen alive.
+                    // It's good for debugging.
+                    _workerThreads[Thread.CurrentThread] = DateTime.Now;
+
+                    // Wait for a work item, shutdown, or timeout
+                    WorkItem workItem = Dequeue();
+
+                    // Update the last time this thread was seen alive.
+                    // It's good for debugging.
+                    _workerThreads[Thread.CurrentThread] = DateTime.Now;
+
+                    // On timeout or shut down.
+                    if (null == workItem)
+                    {
+                        // Double lock for quit.
+                        if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads)
+                        {
+                            lock(_workerThreads.SyncRoot)
+                            {
+                                if (_workerThreads.Count > _stpStartInfo.MinWorkerThreads)
+                                {
+                                    // Inform that the thread is quiting and then quit.
+                                    // This method must be called within this lock or else
+                                    // more threads will quit and the thread pool will go
+                                    // below the lower limit.
+                                    InformCompleted();
+                                    break;
+                                }
+                            }
+                        }
+                    }
+
+                    // If we didn't quit then skip to the next iteration.
+                    if (null == workItem)
+                    {
+                        continue;
+                    }
+
+                    try 
+                    {
+                        // Initialize the value to false
+                        bInUseWorkerThreadsWasIncremented = false;
+
+                        // Change the state of the work item to 'in progress' if possible.
+                        // We do it here so if the work item has been canceled we won't 
+                        // increment the _inUseWorkerThreads.
+                        // The cancel mechanism doesn't delete items from the queue,  
+                        // it marks the work item as canceled, and when the work item
+                        // is dequeued, we just skip it.
+                        // If the post execute of work item is set to always or to
+                        // call when the work item is canceled then the StartingWorkItem()
+                        // will return true, so the post execute can run.
+                        if (!workItem.StartingWorkItem())
+                        {
+                            continue;
+                        }
+
+                        // Execute the callback.  Make sure to accurately
+                        // record how many callbacks are currently executing.
+                        int inUseWorkerThreads = Interlocked.Increment(ref _inUseWorkerThreads);
+                        _pcs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
+
+                        // Mark that the _inUseWorkerThreads incremented, so in the finally{}
+                        // statement we will decrement it correctly.
+                        bInUseWorkerThreadsWasIncremented = true;
+
+                        // Set the _currentWorkItem to the current work item
+                        _currentWorkItem = workItem;
+
+                        lock(workItem)
+                        {
+                            workItem.currentThread = Thread.CurrentThread;
+                        }
+
+                        ExecuteWorkItem(workItem);
+
+                        lock(workItem)
+                        {
+                            workItem.currentThread = null;
+                        }
+
+                    }
+                    catch(ThreadAbortException ex)
+                    {
+                        lock(workItem)
+                        {
+                            workItem.currentThread = null;
+                        }
+                        ex.GetHashCode();
+                        Thread.ResetAbort();
+                    }
+                    catch(Exception ex)
+                    {
+                        ex.GetHashCode();
+                        // Do nothing
+                    }
+                    finally
+                    {
+                        lock(workItem)
+                        {
+                            workItem.currentThread = null;
+                        }
+
+                        if (null != workItem)
+                        {
+                            workItem.DisposeOfState();
+                        }
+
+                        // Set the _currentWorkItem to null, since we 
+                        // no longer run user's code.
+                        _currentWorkItem = null;
+
+                        // Decrement the _inUseWorkerThreads only if we had 
+                        // incremented it. Note the cancelled work items don't
+                        // increment _inUseWorkerThreads.
+                        if (bInUseWorkerThreadsWasIncremented)
+                        {
+                            int inUseWorkerThreads = Interlocked.Decrement(ref _inUseWorkerThreads);
+                            _pcs.SampleThreads(_workerThreads.Count, inUseWorkerThreads);
+                        }
+
+                        // Notify that the work item has been completed.
+                        // WorkItemsGroup may enqueue their next work item.
+                        workItem.FireWorkItemCompleted();
+
+                        // Decrement the number of work items here so the idle 
+                        // ManualResetEvent won't fluctuate.
+                        DecrementWorkItemsCount();
+                    }
+                }
+            } 
+            catch(ThreadAbortException tae)
+            {
+                tae.GetHashCode();
+                // Handle the abort exception gracfully.
+                Thread.ResetAbort();
+            }
+            catch(Exception e)
+            {
+                Debug.Assert(null != e);
+            }
+            finally
+            {
+                InformCompleted();
+            }
+        }
+
+        private void ExecuteWorkItem(WorkItem workItem)
+        {
+            _pcs.SampleWorkItemsWaitTime(workItem.WaitingTime);
+            try
+            {
+                workItem.Execute();
+            }
+            catch
+            {
+                throw;
+            }
+            finally
+            {
+                _pcs.SampleWorkItemsProcessTime(workItem.ProcessTime);
+            }
+        }
+
+
+        #endregion
+
+        #region Public Methods
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
+        {
+            ValidateNotDisposed();
+            ValidateCallback(callback);
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback);
+            Enqueue(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="workItemPriority">The priority of the work item</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority)
+        {
+            ValidateNotDisposed();
+            ValidateCallback(callback);
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, workItemPriority);
+            Enqueue(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="workItemInfo">Work item info</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback)
+        {
+            ValidateNotDisposed();
+            ValidateCallback(callback);
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, workItemInfo, callback);
+            Enqueue(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
+        {
+            ValidateNotDisposed();
+            ValidateCallback(callback);
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state);
+            Enqueue(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="workItemPriority">The work item priority</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority)
+        {
+            ValidateNotDisposed();
+            ValidateCallback(callback);
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, workItemPriority);
+            Enqueue(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="workItemInfo">Work item information</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state)
+        {
+            ValidateNotDisposed();
+            ValidateCallback(callback);
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, workItemInfo, callback, state);
+            Enqueue(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback)
+        {
+            ValidateNotDisposed();
+            ValidateCallback(callback);
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback);
+            Enqueue(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <param name="workItemPriority">The work item priority</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+            WorkItemPriority workItemPriority)
+        {
+            ValidateNotDisposed();
+            ValidateCallback(callback);
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
+            Enqueue(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+            CallToPostExecute callToPostExecute)
+        {
+            ValidateNotDisposed();
+            ValidateCallback(callback);
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
+            Enqueue(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
+        /// <param name="workItemPriority">The work item priority</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+            CallToPostExecute callToPostExecute,
+            WorkItemPriority workItemPriority)
+        {
+            ValidateNotDisposed();
+            ValidateCallback(callback);
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _stpStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority);
+            Enqueue(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Wait for the thread pool to be idle
+        /// </summary>
+        public void WaitForIdle()
+        {
+            WaitForIdle(Timeout.Infinite);
+        }
+
+        /// <summary>
+        /// Wait for the thread pool to be idle
+        /// </summary>
+        public bool WaitForIdle(TimeSpan timeout)
+        {
+            return WaitForIdle((int)timeout.TotalMilliseconds);
+        }
+
+        /// <summary>
+        /// Wait for the thread pool to be idle
+        /// </summary>
+        public bool WaitForIdle(int millisecondsTimeout)
+        {
+            ValidateWaitForIdle();
+            return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false);
+        }
+
+        private void ValidateWaitForIdle()
+        {
+            if(_smartThreadPool == this)
+            {
+                throw new NotSupportedException(
+                    "WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock");
+            }
+        }
+
+        internal void ValidateWorkItemsGroupWaitForIdle(IWorkItemsGroup workItemsGroup)
+        {
+            ValidateWorkItemsGroupWaitForIdleImpl(workItemsGroup, SmartThreadPool._currentWorkItem);
+            if ((null != workItemsGroup) && 
+                (null != SmartThreadPool._currentWorkItem) &&
+                SmartThreadPool._currentWorkItem.WasQueuedBy(workItemsGroup))
+            {
+                throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock");
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private void ValidateWorkItemsGroupWaitForIdleImpl(IWorkItemsGroup workItemsGroup, WorkItem workItem)
+        {
+            if ((null != workItemsGroup) && 
+                (null != workItem) &&
+                workItem.WasQueuedBy(workItemsGroup))
+            {
+                throw new NotSupportedException("WaitForIdle cannot be called from a thread on its SmartThreadPool, it will cause may cause a deadlock");
+            }
+        }
+
+
+
+        /// <summary>
+        /// Force the SmartThreadPool to shutdown
+        /// </summary>
+        public void Shutdown()
+        {
+            Shutdown(true, 0);
+        }
+
+        public void Shutdown(bool forceAbort, TimeSpan timeout)
+        {
+            Shutdown(forceAbort, (int)timeout.TotalMilliseconds);
+        }
+
+        /// <summary>
+        /// Empties the queue of work items and abort the threads in the pool.
+        /// </summary>
+        public void Shutdown(bool forceAbort, int millisecondsTimeout)
+        {
+            ValidateNotDisposed();
+
+            ISTPInstancePerformanceCounters pcs = _pcs;
+
+            if (NullSTPInstancePerformanceCounters.Instance != _pcs)
+            {
+                _pcs.Dispose();
+                // Set the _pcs to "null" to stop updating the performance
+                // counters
+                _pcs = NullSTPInstancePerformanceCounters.Instance;
+            }
+
+            Thread [] threads = null;
+            lock(_workerThreads.SyncRoot)
+            {
+                // Shutdown the work items queue
+                _workItemsQueue.Dispose();
+
+                // Signal the threads to exit
+                _shutdown = true;
+                _shuttingDownEvent.Set();
+
+                // Make a copy of the threads' references in the pool
+                threads = new Thread [_workerThreads.Count];
+                _workerThreads.Keys.CopyTo(threads, 0);
+            }
+
+            int millisecondsLeft = millisecondsTimeout;
+            DateTime start = DateTime.Now;
+            bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
+            bool timeout = false;
+
+            // Each iteration we update the time left for the timeout.
+            foreach(Thread thread in threads)
+            {
+                // Join don't work with negative numbers
+                if (!waitInfinitely && (millisecondsLeft < 0))
+                {
+                    timeout = true;
+                    break;
+                }
+
+                // Wait for the thread to terminate
+                bool success = thread.Join(millisecondsLeft);
+                if(!success)
+                {
+                    timeout = true;
+                    break;
+                }
+
+                if(!waitInfinitely)
+                {
+                    // Update the time left to wait
+                    TimeSpan ts = DateTime.Now - start;
+                    millisecondsLeft = millisecondsTimeout - (int)ts.TotalMilliseconds;
+                }
+            }
+
+            if (timeout && forceAbort)
+            {
+                // Abort the threads in the pool
+                foreach(Thread thread in threads)
+                {
+                    if ((thread != null) && thread.IsAlive) 
+                    {
+                        try 
+                        {
+                            thread.Abort("Shutdown");
+                        }
+                        catch(SecurityException e)
+                        {
+                            e.GetHashCode();
+                        }
+                        catch(ThreadStateException ex)
+                        {
+                            ex.GetHashCode();
+                            // In case the thread has been terminated 
+                            // after the check if it is alive.
+                        }
+                    }
+                }
+            }
+
+            // Dispose of the performance counters
+            pcs.Dispose();
+        }
+
+        /// <summary>
+        /// Wait for all work items to complete
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <returns>
+        /// true when every work item in workItemResults has completed; otherwise false.
+        /// </returns>
+        public static bool WaitAll(
+            IWorkItemResult [] workItemResults)
+        {
+            return WaitAll(workItemResults, Timeout.Infinite, true);
+        }
+
+        /// <summary>
+        /// Wait for all work items to complete
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <returns>
+        /// true when every work item in workItemResults has completed; otherwise false.
+        /// </returns>
+        public static bool WaitAll(
+            IWorkItemResult [] workItemResults,
+            TimeSpan timeout,
+            bool exitContext)
+        {
+            return WaitAll(workItemResults, (int)timeout.TotalMilliseconds, exitContext);
+        }
+
+        /// <summary>
+        /// Wait for all work items to complete
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
+        /// <returns>
+        /// true when every work item in workItemResults has completed; otherwise false.
+        /// </returns>
+        public static bool WaitAll(
+            IWorkItemResult [] workItemResults,  
+            TimeSpan timeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle)
+        {
+            return WaitAll(workItemResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
+        }
+
+        /// <summary>
+        /// Wait for all work items to complete
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <returns>
+        /// true when every work item in workItemResults has completed; otherwise false.
+        /// </returns>
+        public static bool WaitAll(
+            IWorkItemResult [] workItemResults,  
+            int millisecondsTimeout,
+            bool exitContext)
+        {
+            return WorkItem.WaitAll(workItemResults, millisecondsTimeout, exitContext, null);
+        }
+
+        /// <summary>
+        /// Wait for all work items to complete
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
+        /// <returns>
+        /// true when every work item in workItemResults has completed; otherwise false.
+        /// </returns>
+        public static bool WaitAll(
+            IWorkItemResult [] workItemResults,  
+            int millisecondsTimeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle)
+        {
+            return WorkItem.WaitAll(workItemResults, millisecondsTimeout, exitContext, cancelWaitHandle);
+        }
+
+
+        /// <summary>
+        /// Waits for any of the work items in the specified array to complete, cancel, or timeout
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <returns>
+        /// The array index of the work item result that satisfied the wait, or WaitTimeout if any of the work items has been canceled.
+        /// </returns>
+        public static int WaitAny(
+            IWorkItemResult [] workItemResults)
+        {
+            return WaitAny(workItemResults, Timeout.Infinite, true);
+        }
+
+        /// <summary>
+        /// Waits for any of the work items in the specified array to complete, cancel, or timeout
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <returns>
+        /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
+        /// </returns>
+        public static int WaitAny(
+            IWorkItemResult [] workItemResults,
+            TimeSpan timeout,
+            bool exitContext)
+        {
+            return WaitAny(workItemResults, (int)timeout.TotalMilliseconds, exitContext);
+        }
+
+        /// <summary>
+        /// Waits for any of the work items in the specified array to complete, cancel, or timeout
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <param name="timeout">The number of milliseconds to wait, or a TimeSpan that represents -1 milliseconds to wait indefinitely. </param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
+        /// <returns>
+        /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
+        /// </returns>
+        public static int WaitAny(
+            IWorkItemResult [] workItemResults,
+            TimeSpan timeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle)
+        {
+            return WaitAny(workItemResults, (int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
+        }
+
+        /// <summary>
+        /// Waits for any of the work items in the specified array to complete, cancel, or timeout
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <returns>
+        /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
+        /// </returns>
+        public static int WaitAny(
+            IWorkItemResult [] workItemResults,  
+            int millisecondsTimeout,
+            bool exitContext)
+        {
+            return WorkItem.WaitAny(workItemResults, millisecondsTimeout, exitContext, null);
+        }
+
+        /// <summary>
+        /// Waits for any of the work items in the specified array to complete, cancel, or timeout
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
+        /// <returns>
+        /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
+        /// </returns>
+        public static int WaitAny(
+            IWorkItemResult [] workItemResults,  
+            int millisecondsTimeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle)
+        {
+            return WorkItem.WaitAny(workItemResults, millisecondsTimeout, exitContext, cancelWaitHandle);
+        }
+
+        public IWorkItemsGroup CreateWorkItemsGroup(int concurrency)
+        {
+            IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, _stpStartInfo);
+            return workItemsGroup;
+        }
+
+        public IWorkItemsGroup CreateWorkItemsGroup(int concurrency, WIGStartInfo wigStartInfo)
+        {
+            IWorkItemsGroup workItemsGroup = new WorkItemsGroup(this, concurrency, wigStartInfo);
+            return workItemsGroup;
+        }
+
+        public event WorkItemsGroupIdleHandler OnIdle
+        {
+            add
+            {
+                throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature.");
+                //_onIdle += value;
+            }
+            remove
+            {
+                throw new NotImplementedException("This event is not implemented in the SmartThreadPool class. Please create a WorkItemsGroup in order to use this feature.");
+                //_onIdle -= value;
+            }
+        }
+
+        public void Cancel()
+        {
+            ICollection workItemsGroups = _workItemsGroups.Values;
+            foreach(WorkItemsGroup workItemsGroup in workItemsGroups)
+            {
+                workItemsGroup.Cancel();
+            }
+        }
+
+        public void Start()
+        {
+            lock (this)
+            {
+                if (!this._stpStartInfo.StartSuspended)
+                {
+                    return;
+                }
+                _stpStartInfo.StartSuspended = false;
+            }
+            
+            ICollection workItemsGroups = _workItemsGroups.Values;
+            foreach(WorkItemsGroup workItemsGroup in workItemsGroups)
+            {
+                workItemsGroup.OnSTPIsStarting();
+            }
+
+            StartOptimalNumberOfThreads();
+        }
+
+        #endregion
+
+        #region Properties
+
+        /// <summary>
+        /// Get/Set the name of the SmartThreadPool instance
+        /// </summary>
+        public string Name 
+        { 
+            get
+            {
+                return _name;
+            }
+
+            set
+            {
+                _name = value;
+            }
+        }
+
+        /// <summary>
+        /// Get the lower limit of threads in the pool.
+        /// </summary>
+        public int MinThreads 
+        { 
+            get 
+            {
+                ValidateNotDisposed();
+                return _stpStartInfo.MinWorkerThreads; 
+            }
+        }
+
+        /// <summary>
+        /// Get the upper limit of threads in the pool.
+        /// </summary>
+        public int MaxThreads 
+        { 
+            get 
+            {
+                ValidateNotDisposed();
+                return _stpStartInfo.MaxWorkerThreads; 
+            } 
+        }
+        /// <summary>
+        /// Get the number of threads in the thread pool.
+        /// Should be between the lower and the upper limits.
+        /// </summary>
+        public int ActiveThreads 
+        { 
+            get 
+            {
+                ValidateNotDisposed();
+                return _workerThreads.Count; 
+            } 
+        }
+
+        /// <summary>
+        /// Get the number of busy (not idle) threads in the thread pool.
+        /// </summary>
+        public int InUseThreads 
+        { 
+            get 
+            { 
+                ValidateNotDisposed();
+                return _inUseWorkerThreads; 
+            } 
+        }
+
+        /// <summary>
+        /// Get the number of work items in the queue.
+        /// </summary>
+        public int WaitingCallbacks 
+        { 
+            get 
+            { 
+                ValidateNotDisposed();
+                return _workItemsQueue.Count;
+            } 
+        }
+
+
+        public event EventHandler Idle
+        {
+            add
+            {
+                _stpIdle += value;
+            }
+
+            remove
+            {
+                _stpIdle -= value;
+            }
+        }
+
+        #endregion
+
+        #region IDisposable Members
+
+//        ~SmartThreadPool()
+//        {
+//            Dispose();
+//        }
+
+        public void Dispose()
+        {
+            if (!_isDisposed)
+            {
+                if (!_shutdown)
+                {
+                    Shutdown();
+                }
+
+                if (null != _shuttingDownEvent)
+                {
+                    _shuttingDownEvent.Close();
+                    _shuttingDownEvent = null;
+                }
+                _workerThreads.Clear();
+                _isDisposed = true;
+                GC.SuppressFinalize(this);
+            }
+        }
+
+        private void ValidateNotDisposed()
+        {
+            if(_isDisposed)
+            {
+                throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown");
+            }
+        }
+        #endregion
+    }
+    #endregion
+}

+ 99 - 0
ThirdParty/SmartThreadPool/WIGStartInfo.cs

@@ -0,0 +1,99 @@
+// Ami Bar
+// [email protected]
+
+namespace Amib.Threading
+{
+    /// <summary>
+    /// Summary description for WIGStartInfo.
+    /// </summary>
+    public class WIGStartInfo
+    {
+        /// <summary>
+        /// Use the caller's security context
+        /// </summary>
+        private bool _useCallerCallContext;
+
+        /// <summary>
+        /// Use the caller's HTTP context
+        /// </summary>
+        private bool _useCallerHttpContext;
+
+        /// <summary>
+        /// Dispose of the state object of a work item
+        /// </summary>
+        private bool _disposeOfStateObjects;
+
+        /// <summary>
+        /// The option to run the post execute
+        /// </summary>
+        private CallToPostExecute _callToPostExecute;
+
+        /// <summary>
+        /// A post execute callback to call when none is provided in 
+        /// the QueueWorkItem method.
+        /// </summary>
+        private PostExecuteWorkItemCallback _postExecuteWorkItemCallback;
+
+        /// <summary>
+        /// Indicate the WorkItemsGroup to suspend the handling of the work items
+        /// until the Start() method is called.
+        /// </summary>
+        private bool _startSuspended;
+
+        public WIGStartInfo()
+        {
+            _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
+            _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
+            _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
+            _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
+            _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
+            _startSuspended = SmartThreadPool.DefaultStartSuspended;
+        }
+
+        public WIGStartInfo(WIGStartInfo wigStartInfo)
+        {
+            _useCallerCallContext = wigStartInfo._useCallerCallContext;
+            _useCallerHttpContext = wigStartInfo._useCallerHttpContext;
+            _disposeOfStateObjects = wigStartInfo._disposeOfStateObjects;
+            _callToPostExecute = wigStartInfo._callToPostExecute;
+            _postExecuteWorkItemCallback = wigStartInfo._postExecuteWorkItemCallback;
+            _startSuspended = wigStartInfo._startSuspended;
+        }
+
+        public bool UseCallerCallContext
+        {
+            get { return _useCallerCallContext; }
+            set { _useCallerCallContext = value; }
+        }
+
+        public bool UseCallerHttpContext
+        {
+            get { return _useCallerHttpContext; }
+            set { _useCallerHttpContext = value; }
+        }
+
+        public bool DisposeOfStateObjects
+        {
+            get { return _disposeOfStateObjects; }
+            set { _disposeOfStateObjects = value; }
+        }
+
+        public CallToPostExecute CallToPostExecute
+        {
+            get { return _callToPostExecute; }
+            set { _callToPostExecute = value; }
+        }
+
+        public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
+        {
+            get { return _postExecuteWorkItemCallback; }
+            set { _postExecuteWorkItemCallback = value; }
+        }
+
+        public bool StartSuspended
+        {
+            get { return _startSuspended; }
+            set { _startSuspended = value; }
+        }
+    }
+}

+ 1035 - 0
ThirdParty/SmartThreadPool/WorkItem.cs

@@ -0,0 +1,1035 @@
+// Ami Bar
+// [email protected]
+
+using System;
+using System.Threading;
+using System.Diagnostics;
+
+namespace Amib.Threading.Internal
+{
+    #region WorkItem Delegate
+
+    /// <summary>
+    /// An internal delegate to call when the WorkItem starts or completes
+    /// </summary>
+    internal delegate void WorkItemStateCallback(WorkItem workItem);
+
+    #endregion
+
+    #region IInternalWorkItemResult interface 
+
+    public class CanceledWorkItemsGroup
+    {
+        public readonly static CanceledWorkItemsGroup NotCanceledWorkItemsGroup = new CanceledWorkItemsGroup();
+
+        private bool _isCanceled = false;
+        public bool IsCanceled 
+        { 
+            get { return _isCanceled; }
+            set { _isCanceled = value; }
+        }
+    }
+
+    internal interface IInternalWorkItemResult
+    {
+        event WorkItemStateCallback OnWorkItemStarted;
+        event WorkItemStateCallback OnWorkItemCompleted;
+    }
+
+    #endregion
+
+    #region IWorkItem interface
+
+    public interface IWorkItem
+    {
+
+    }
+
+    #endregion
+
+    #region WorkItem class
+
+    /// <summary>
+    /// Holds a callback delegate and the state for that delegate.
+    /// </summary>
+    public class WorkItem : IHasWorkItemPriority, IWorkItem
+    {
+        #region WorkItemState enum
+
+        /// <summary>
+        /// Indicates the state of the work item in the thread pool
+        /// </summary>
+        private enum WorkItemState
+        {
+            InQueue,
+            InProgress,
+            Completed,
+            Canceled,
+        }
+
+        #endregion
+
+        #region Member Variables
+
+        public Thread currentThread;
+
+        /// <summary>
+        /// Callback delegate for the callback.
+        /// </summary>
+        private WorkItemCallback _callback;
+
+        /// <summary>
+        /// State with which to call the callback delegate.
+        /// </summary>
+        private object _state;
+
+        /// <summary>
+        /// Stores the caller's context
+        /// </summary>
+        private CallerThreadContext _callerContext;
+
+        /// <summary>
+        /// Holds the result of the mehtod
+        /// </summary>
+        private object _result;
+
+        /// <summary>
+        /// Hold the exception if the method threw it
+        /// </summary>
+        private Exception _exception;
+
+        /// <summary>
+        /// Hold the state of the work item
+        /// </summary>
+        private WorkItemState _workItemState;
+
+        /// <summary>
+        /// A ManualResetEvent to indicate that the result is ready
+        /// </summary>
+        private ManualResetEvent _workItemCompleted;
+
+        /// <summary>
+        /// A reference count to the _workItemCompleted. 
+        /// When it reaches to zero _workItemCompleted is Closed
+        /// </summary>
+        private int _workItemCompletedRefCount;
+
+        /// <summary>
+        /// Represents the result state of the work item
+        /// </summary>
+        private WorkItemResult _workItemResult;
+
+        /// <summary>
+        /// Work item info
+        /// </summary>
+        private WorkItemInfo _workItemInfo;
+
+        /// <summary>
+        /// Called when the WorkItem starts
+        /// </summary>
+        private event WorkItemStateCallback _workItemStartedEvent;
+
+        /// <summary>
+        /// Called when the WorkItem completes
+        /// </summary>
+        private event WorkItemStateCallback _workItemCompletedEvent;
+
+        /// <summary>
+        /// A reference to an object that indicates whatever the 
+        /// WorkItemsGroup has been canceled
+        /// </summary>
+        private CanceledWorkItemsGroup _canceledWorkItemsGroup = CanceledWorkItemsGroup.NotCanceledWorkItemsGroup;
+
+        /// <summary>
+        /// The work item group this work item belong to.
+        /// 
+        /// </summary>
+        private IWorkItemsGroup _workItemsGroup;
+
+        #region Performance Counter fields
+
+        /// <summary>
+        /// The time when the work items is queued.
+        /// Used with the performance counter.
+        /// </summary>
+        private DateTime _queuedTime;
+
+        /// <summary>
+        /// The time when the work items starts its execution.
+        /// Used with the performance counter.
+        /// </summary>
+        private DateTime _beginProcessTime;
+
+        /// <summary>
+        /// The time when the work items ends its execution.
+        /// Used with the performance counter.
+        /// </summary>
+        private DateTime _endProcessTime;
+
+        #endregion
+
+        #endregion
+
+        #region Properties
+
+        public TimeSpan WaitingTime
+        {
+            get 
+            {
+                return (_beginProcessTime - _queuedTime);
+            }
+        }
+
+        public TimeSpan ProcessTime
+        {
+            get 
+            {
+                return (_endProcessTime - _beginProcessTime);
+            }
+        }
+
+        #endregion
+
+        #region Construction
+
+        /// <summary>
+        /// Initialize the callback holding object.
+        /// </summary>
+        /// <param name="callback">Callback delegate for the callback.</param>
+        /// <param name="state">State with which to call the callback delegate.</param>
+        /// 
+        /// We assume that the WorkItem object is created within the thread
+        /// that meant to run the callback
+        public WorkItem(
+            IWorkItemsGroup workItemsGroup,
+            WorkItemInfo workItemInfo,
+            WorkItemCallback callback, 
+            object state)
+        {
+            _workItemsGroup = workItemsGroup;
+            _workItemInfo = workItemInfo;
+
+            if (_workItemInfo.UseCallerCallContext || _workItemInfo.UseCallerHttpContext)
+            {
+                _callerContext = CallerThreadContext.Capture(_workItemInfo.UseCallerCallContext, _workItemInfo.UseCallerHttpContext);
+            }
+
+            _callback = callback;
+            _state = state;
+            _workItemResult = new WorkItemResult(this);
+            Initialize();
+        }
+
+        internal void Initialize()
+        {
+            _workItemState = WorkItemState.InQueue;
+            _workItemCompleted = null;
+            _workItemCompletedRefCount = 0;
+        }
+
+        internal bool WasQueuedBy(IWorkItemsGroup workItemsGroup)
+        {
+            return (workItemsGroup == _workItemsGroup);
+        }
+
+
+        #endregion
+
+        #region Methods
+
+        public CanceledWorkItemsGroup CanceledWorkItemsGroup
+        {
+            get
+            {
+                return _canceledWorkItemsGroup;
+            }
+
+            set
+            {
+                _canceledWorkItemsGroup = value;
+            }
+        }
+
+        /// <summary>
+        /// Change the state of the work item to in progress if it wasn't canceled.
+        /// </summary>
+        /// <returns>
+        /// Return true on success or false in case the work item was canceled.
+        /// If the work item needs to run a post execute then the method will return true.
+        /// </returns>
+        public bool StartingWorkItem()
+        {
+            _beginProcessTime = DateTime.Now;
+
+            lock(this)
+            {
+                if (IsCanceled)
+                {
+                    bool result = false;
+                    if ((_workItemInfo.PostExecuteWorkItemCallback != null) &&
+                        ((_workItemInfo.CallToPostExecute & CallToPostExecute.WhenWorkItemCanceled) == CallToPostExecute.WhenWorkItemCanceled))
+                    {
+                        result = true;
+                    }
+
+                    return result;
+                }
+
+                Debug.Assert(WorkItemState.InQueue == GetWorkItemState());
+
+                SetWorkItemState(WorkItemState.InProgress);
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// Execute the work item and the post execute
+        /// </summary>
+        public void Execute()
+        {
+            CallToPostExecute currentCallToPostExecute = 0;
+
+            // Execute the work item if we are in the correct state
+            switch(GetWorkItemState())
+            {
+                case WorkItemState.InProgress:
+                    currentCallToPostExecute |= CallToPostExecute.WhenWorkItemNotCanceled;
+                    ExecuteWorkItem();
+                    break;
+                case WorkItemState.Canceled:
+                    currentCallToPostExecute |= CallToPostExecute.WhenWorkItemCanceled;
+                    break;
+                default:
+                    Debug.Assert(false);
+                    throw new NotSupportedException();
+            }
+
+            // Run the post execute as needed
+            if ((currentCallToPostExecute & _workItemInfo.CallToPostExecute) != 0)
+            {
+                PostExecute();
+            }
+
+            _endProcessTime = DateTime.Now;
+        }
+
+        internal void FireWorkItemCompleted()
+        {
+            try
+            {
+                if (null != _workItemCompletedEvent)
+                {
+                    _workItemCompletedEvent(this);
+                }
+            }
+            catch // Ignore exceptions
+            {}
+        }
+
+        /// <summary>
+        /// Execute the work item
+        /// </summary>
+        private void ExecuteWorkItem()
+        {
+            CallerThreadContext ctc = null;
+            if (null != _callerContext)
+            {
+                ctc = CallerThreadContext.Capture(_callerContext.CapturedCallContext, _callerContext.CapturedHttpContext);
+                CallerThreadContext.Apply(_callerContext);
+            }
+
+            Exception exception = null;
+            object result = null;
+
+            try
+            {
+                result = _callback(_state);
+            }
+            catch (Exception e) 
+            {
+                // Save the exception so we can rethrow it later
+                exception = e;
+            }
+        
+            if (null != _callerContext)
+            {
+                CallerThreadContext.Apply(ctc);
+            }
+
+            SetResult(result, exception);
+        }
+
+        /// <summary>
+        /// Runs the post execute callback
+        /// </summary>
+        private void PostExecute()
+        {
+            if (null != _workItemInfo.PostExecuteWorkItemCallback)
+            {
+                try
+                {
+                    _workItemInfo.PostExecuteWorkItemCallback(this._workItemResult);
+                }
+                catch (Exception e) 
+                {
+                    Debug.Assert(null != e);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Set the result of the work item to return
+        /// </summary>
+        /// <param name="result">The result of the work item</param>
+        internal void SetResult(object result, Exception exception)
+        {
+            _result = result;
+            _exception = exception;
+            SignalComplete(false);
+        }
+
+        /// <summary>
+        /// Returns the work item result
+        /// </summary>
+        /// <returns>The work item result</returns>
+        internal IWorkItemResult GetWorkItemResult()
+        {
+            return _workItemResult;
+        }
+
+        /// <summary>
+        /// Wait for all work items to complete
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
+        /// <returns>
+        /// true when every work item in workItemResults has completed; otherwise false.
+        /// </returns>
+        internal static bool WaitAll(
+            IWorkItemResult [] workItemResults,
+            int millisecondsTimeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle)
+        {
+            if (0 == workItemResults.Length)
+            {
+                return true;
+            }
+
+            bool success;
+            WaitHandle [] waitHandles = new WaitHandle[workItemResults.Length];;
+            GetWaitHandles(workItemResults, waitHandles);
+
+            if ((null == cancelWaitHandle) && (waitHandles.Length <= 64))
+            {
+                success = WaitHandle.WaitAll(waitHandles, millisecondsTimeout, exitContext);
+            }
+            else
+            {
+                success = true;
+                int millisecondsLeft = millisecondsTimeout;
+                DateTime start = DateTime.Now;
+
+                WaitHandle [] whs;
+                if (null != cancelWaitHandle)
+                {
+                    whs = new WaitHandle [] { null, cancelWaitHandle };
+                }
+                else
+                {
+                    whs = new WaitHandle [] { null };
+                }
+
+                bool waitInfinitely = (Timeout.Infinite == millisecondsTimeout);
+                // Iterate over the wait handles and wait for each one to complete.
+                // We cannot use WaitHandle.WaitAll directly, because the cancelWaitHandle
+                // won't affect it.
+                // Each iteration we update the time left for the timeout.
+                for(int i = 0; i < workItemResults.Length; ++i)
+                {
+                    // WaitAny don't work with negative numbers
+                    if (!waitInfinitely && (millisecondsLeft < 0))
+                    {
+                        success = false;
+                        break;
+                    }
+
+                    whs[0] = waitHandles[i];
+                    int result = WaitHandle.WaitAny(whs, millisecondsLeft, exitContext);
+                    if((result > 0) || (WaitHandle.WaitTimeout == result))
+                    {
+                        success = false;
+                        break;
+                    }
+
+                    if(!waitInfinitely)
+                    {
+                        // Update the time left to wait
+                        TimeSpan ts = DateTime.Now - start;
+                        millisecondsLeft = millisecondsTimeout - (int)ts.TotalMilliseconds;
+                    }
+                }
+            }
+            // Release the wait handles
+            ReleaseWaitHandles(workItemResults);
+
+            return success;
+        }
+
+        /// <summary>
+        /// Waits for any of the work items in the specified array to complete, cancel, or timeout
+        /// </summary>
+        /// <param name="workItemResults">Array of work item result objects</param>
+        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or Timeout.Infinite (-1) to wait indefinitely.</param>
+        /// <param name="exitContext">
+        /// true to exit the synchronization domain for the context before the wait (if in a synchronized context), and reacquire it; otherwise, false. 
+        /// </param>
+        /// <param name="cancelWaitHandle">A cancel wait handle to interrupt the wait if needed</param>
+        /// <returns>
+        /// The array index of the work item result that satisfied the wait, or WaitTimeout if no work item result satisfied the wait and a time interval equivalent to millisecondsTimeout has passed or the work item has been canceled.
+        /// </returns>
+        internal static int WaitAny(            
+            IWorkItemResult [] workItemResults,
+            int millisecondsTimeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle)
+        {
+            WaitHandle [] waitHandles = null;
+
+            if (null != cancelWaitHandle)
+            {
+                waitHandles = new WaitHandle[workItemResults.Length+1];
+                GetWaitHandles(workItemResults, waitHandles);
+                waitHandles[workItemResults.Length] = cancelWaitHandle;
+            }
+            else
+            {
+                waitHandles = new WaitHandle[workItemResults.Length];
+                GetWaitHandles(workItemResults, waitHandles);
+            }
+
+            int result = WaitHandle.WaitAny(waitHandles, millisecondsTimeout, exitContext);
+
+            // Treat cancel as timeout
+            if (null != cancelWaitHandle)
+            {
+                if (result == workItemResults.Length)
+                {
+                    result = WaitHandle.WaitTimeout;
+                }
+            }
+
+            ReleaseWaitHandles(workItemResults);
+
+            return result;
+        }
+
+        /// <summary>
+        /// Fill an array of wait handles with the work items wait handles.
+        /// </summary>
+        /// <param name="workItemResults">An array of work item results</param>
+        /// <param name="waitHandles">An array of wait handles to fill</param>
+        private static void GetWaitHandles(
+            IWorkItemResult [] workItemResults,
+            WaitHandle [] waitHandles)
+        {
+            for(int i = 0; i < workItemResults.Length; ++i)
+            {
+                WorkItemResult wir = workItemResults[i] as WorkItemResult;
+                Debug.Assert(null != wir, "All workItemResults must be WorkItemResult objects");
+
+                waitHandles[i] = wir.GetWorkItem().GetWaitHandle();
+            }
+        }
+
+        /// <summary>
+        /// Release the work items' wait handles
+        /// </summary>
+        /// <param name="workItemResults">An array of work item results</param>
+        private static void ReleaseWaitHandles(IWorkItemResult [] workItemResults)
+        {
+            for(int i = 0; i < workItemResults.Length; ++i)
+            {
+                WorkItemResult wir = workItemResults[i] as WorkItemResult;
+
+                wir.GetWorkItem().ReleaseWaitHandle();
+            }
+        }
+
+
+        #endregion
+        
+        #region Private Members
+
+        private WorkItemState GetWorkItemState()
+        {
+            if (_canceledWorkItemsGroup.IsCanceled)
+            {
+                return WorkItemState.Canceled;
+            }
+            return _workItemState;
+
+        }
+        /// <summary>
+        /// Sets the work item's state
+        /// </summary>
+        /// <param name="workItemState">The state to set the work item to</param>
+        private void SetWorkItemState(WorkItemState workItemState)
+        {
+            lock(this)
+            {
+                _workItemState = workItemState;
+            }
+        }
+
+        /// <summary>
+        /// Signals that work item has been completed or canceled
+        /// </summary>
+        /// <param name="canceled">Indicates that the work item has been canceled</param>
+        private void SignalComplete(bool canceled)
+        {
+            SetWorkItemState(canceled ? WorkItemState.Canceled : WorkItemState.Completed);
+            lock(this)
+            {
+                // If someone is waiting then signal.
+                if (null != _workItemCompleted)
+                {
+                    _workItemCompleted.Set();
+                }
+            }
+        }
+
+        internal void WorkItemIsQueued()
+        {
+            _queuedTime = DateTime.Now;
+        }
+
+        #endregion
+        
+        #region Members exposed by WorkItemResult
+
+        /// <summary>
+        /// Cancel the work item if it didn't start running yet.
+        /// </summary>
+        /// <returns>Returns true on success or false if the work item is in progress or already completed</returns>
+        private bool Cancel()
+        {
+            lock(this)
+            {
+                switch(GetWorkItemState())
+                {
+                    case WorkItemState.Canceled:
+                        //Debug.WriteLine("Work item already canceled");
+                        return true;
+                    case WorkItemState.Completed:
+                    case WorkItemState.InProgress:
+                        //Debug.WriteLine("Work item cannot be canceled");
+                        return false;
+                    case WorkItemState.InQueue:
+                        // Signal to the wait for completion that the work
+                        // item has been completed (canceled). There is no
+                        // reason to wait for it to get out of the queue
+                        SignalComplete(true);
+                        //Debug.WriteLine("Work item canceled");
+                        return true;
+                }
+            }
+            return false;
+        }
+
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits for the result, timeout, or cancel.
+        /// In case of error the method throws and exception
+        /// </summary>
+        /// <returns>The result of the work item</returns>
+        private object GetResult(
+            int millisecondsTimeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle)
+        {
+            Exception e = null;
+            object result = GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
+            if (null != e)
+            {
+                throw new WorkItemResultException("The work item caused an excpetion, see the inner exception for details", e);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// Get the result of the work item.
+        /// If the work item didn't run yet then the caller waits for the result, timeout, or cancel.
+        /// In case of error the e argument is filled with the exception
+        /// </summary>
+        /// <returns>The result of the work item</returns>
+        private object GetResult(
+            int millisecondsTimeout,
+            bool exitContext,
+            WaitHandle cancelWaitHandle,
+            out Exception e)
+        {
+            e = null;
+
+            // Check for cancel
+            if (WorkItemState.Canceled == GetWorkItemState())
+            {
+                throw new WorkItemCancelException("Work item canceled");
+            }
+
+            // Check for completion
+            if (IsCompleted)
+            {
+                e = _exception;
+                return _result;
+            }
+
+            // If no cancelWaitHandle is provided
+            if (null == cancelWaitHandle)
+            {
+                WaitHandle wh = GetWaitHandle();
+
+                bool timeout = !wh.WaitOne(millisecondsTimeout, exitContext);
+
+                ReleaseWaitHandle();
+
+                if (timeout)
+                {
+                    throw new WorkItemTimeoutException("Work item timeout");
+                }
+            }
+            else
+            {
+                WaitHandle wh = GetWaitHandle();
+                int result = WaitHandle.WaitAny(new WaitHandle[] { wh, cancelWaitHandle });
+                ReleaseWaitHandle();
+
+                switch(result)
+                {
+                    case 0:
+                        // The work item signaled
+                        // Note that the signal could be also as a result of canceling the 
+                        // work item (not the get result)
+                        break;
+                    case 1:
+                    case WaitHandle.WaitTimeout:
+                        throw new WorkItemTimeoutException("Work item timeout");
+                    default:
+                        Debug.Assert(false);
+                        break;
+
+                }
+            }
+
+            // Check for cancel
+            if (WorkItemState.Canceled == GetWorkItemState())
+            {
+                throw new WorkItemCancelException("Work item canceled");
+            }
+
+            Debug.Assert(IsCompleted);
+
+            e = _exception;
+
+            // Return the result
+            return _result;
+        }
+
+        /// <summary>
+        /// A wait handle to wait for completion, cancel, or timeout 
+        /// </summary>
+        private WaitHandle GetWaitHandle()
+        {
+            lock(this)
+            {
+                if (null == _workItemCompleted)
+                {
+                    _workItemCompleted = new ManualResetEvent(IsCompleted);
+                }
+                ++_workItemCompletedRefCount;
+            }
+            return _workItemCompleted;
+        }
+
+        private void ReleaseWaitHandle()
+        {
+            lock(this)
+            {
+                if (null != _workItemCompleted)
+                {
+                    --_workItemCompletedRefCount;
+                    if (0 == _workItemCompletedRefCount)
+                    {
+                        _workItemCompleted.Close();
+                        _workItemCompleted = null;
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Returns true when the work item has completed or canceled
+        /// </summary>
+        private bool IsCompleted
+        {
+            get
+            {
+                lock(this)
+                {
+                    WorkItemState workItemState = GetWorkItemState();
+                    return ((workItemState == WorkItemState.Completed) || 
+                            (workItemState == WorkItemState.Canceled));
+                }
+            }
+        }
+
+        /// <summary>
+        /// Returns true when the work item has canceled
+        /// </summary>
+        public bool IsCanceled
+        {
+            get
+            {
+                lock(this)
+                {
+                    return (GetWorkItemState() == WorkItemState.Canceled);
+                }
+            }
+        }
+
+        #endregion
+
+        #region IHasWorkItemPriority Members
+
+        /// <summary>
+        /// Returns the priority of the work item
+        /// </summary>
+        public WorkItemPriority WorkItemPriority
+        {
+            get
+            {
+                return _workItemInfo.WorkItemPriority;
+            }
+        }
+
+        #endregion
+
+        internal event WorkItemStateCallback OnWorkItemStarted
+        {
+            add
+            {
+                _workItemStartedEvent += value;
+            }
+            remove
+            {
+                _workItemStartedEvent -= value;
+            }
+        }
+
+        internal event WorkItemStateCallback OnWorkItemCompleted
+        {
+            add
+            {
+                _workItemCompletedEvent += value;
+            }
+            remove
+            {
+                _workItemCompletedEvent -= value;
+            }
+        }
+
+
+        #region WorkItemResult class
+
+        private class WorkItemResult : IWorkItemResult, IInternalWorkItemResult
+        {
+            /// <summary>
+            /// A back reference to the work item
+            /// </summary>
+            private WorkItem _workItem;
+
+            public WorkItemResult(WorkItem workItem)
+            {
+                _workItem = workItem;
+            }
+
+            internal WorkItem GetWorkItem()
+            {
+                return _workItem;
+            }
+
+            #region IWorkItemResult Members
+
+            public bool IsCompleted
+            {
+                get
+                {
+                    return _workItem.IsCompleted;
+                }
+            }
+
+            public void Abort()
+            {
+                _workItem.Abort();
+            }
+
+            public bool IsCanceled
+            {
+                get
+                {
+                    return _workItem.IsCanceled;
+                }
+            }
+
+            public object GetResult()
+            {
+                return _workItem.GetResult(Timeout.Infinite, true, null);
+            }
+    
+            public object GetResult(int millisecondsTimeout, bool exitContext)
+            {
+                return _workItem.GetResult(millisecondsTimeout, exitContext, null);
+            }
+
+            public object GetResult(TimeSpan timeout, bool exitContext)
+            {
+                return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null);
+            }
+
+            public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle)
+            {
+                return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle);
+            }
+
+            public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle)
+            {
+                return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle);
+            }
+
+            public object GetResult(out Exception e)
+            {
+                return _workItem.GetResult(Timeout.Infinite, true, null, out e);
+            }
+    
+            public object GetResult(int millisecondsTimeout, bool exitContext, out Exception e)
+            {
+                return _workItem.GetResult(millisecondsTimeout, exitContext, null, out e);
+            }
+
+            public object GetResult(TimeSpan timeout, bool exitContext, out Exception e)
+            {
+                return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, null, out e);
+            }
+
+            public object GetResult(int millisecondsTimeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
+            {
+                return _workItem.GetResult(millisecondsTimeout, exitContext, cancelWaitHandle, out e);
+            }
+
+            public object GetResult(TimeSpan timeout, bool exitContext, WaitHandle cancelWaitHandle, out Exception e)
+            {
+                return _workItem.GetResult((int)timeout.TotalMilliseconds, exitContext, cancelWaitHandle, out e);
+            }
+
+            public bool Cancel()
+            {
+                return _workItem.Cancel();
+            }
+
+            public object State
+            {
+                get
+                {
+                    return _workItem._state;
+                }
+            }
+
+            public WorkItemPriority WorkItemPriority 
+            { 
+                get
+                {
+                    return _workItem._workItemInfo.WorkItemPriority;
+                }
+            }
+
+            /// <summary>
+            /// Return the result, same as GetResult()
+            /// </summary>
+            public object Result
+            {
+                get { return GetResult(); }
+            }
+
+            /// <summary>
+            /// Returns the exception if occured otherwise returns null.
+            /// This value is valid only after the work item completed,
+            /// before that it is always null.
+            /// </summary>
+            public object Exception
+            {
+                get { return _workItem._exception; }
+            }
+
+            #endregion
+
+            #region IInternalWorkItemResult Members
+
+            public event WorkItemStateCallback OnWorkItemStarted
+            {
+                add
+                {
+                    _workItem.OnWorkItemStarted += value;
+                }
+                remove
+                {
+                    _workItem.OnWorkItemStarted -= value;
+                }
+            }
+
+
+            public event WorkItemStateCallback OnWorkItemCompleted
+            {
+                add
+                {
+                    _workItem.OnWorkItemCompleted += value;
+                }
+                remove
+                {
+                    _workItem.OnWorkItemCompleted -= value;
+                }
+            }
+
+            #endregion
+        }
+
+        #endregion
+
+        public void DisposeOfState()
+        {
+            if (_workItemInfo.DisposeOfStateObjects)
+            {
+                IDisposable disp = _state as IDisposable;
+                if (null != disp)
+                {
+                    disp.Dispose();
+                    _state = null;
+                }
+            }
+        }
+
+        public void Abort()
+        {
+            lock (this)
+            {
+                if(currentThread != null)
+                    currentThread.Abort();
+            }
+        }
+    }
+    #endregion
+}

+ 333 - 0
ThirdParty/SmartThreadPool/WorkItemFactory.cs

@@ -0,0 +1,333 @@
+// Ami Bar
+// [email protected]
+
+using System;
+
+namespace Amib.Threading.Internal
+{
+    #region WorkItemFactory class 
+
+    public class WorkItemFactory
+    {
+        /// <summary>
+        /// Create a new work item
+        /// </summary>
+        /// <param name="wigStartInfo">Work item group start information</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <returns>Returns a work item</returns>
+        public static WorkItem CreateWorkItem(
+            IWorkItemsGroup workItemsGroup,
+            WIGStartInfo wigStartInfo,
+            WorkItemCallback callback)
+        {
+            return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null);
+        }
+
+        /// <summary>
+        /// Create a new work item
+        /// </summary>
+        /// <param name="wigStartInfo">Work item group start information</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="workItemPriority">The priority of the work item</param>
+        /// <returns>Returns a work item</returns>
+        public static WorkItem CreateWorkItem(
+            IWorkItemsGroup workItemsGroup,
+            WIGStartInfo wigStartInfo,
+            WorkItemCallback callback, 
+            WorkItemPriority workItemPriority)
+        {
+            return CreateWorkItem(workItemsGroup, wigStartInfo, callback, null, workItemPriority);
+        }
+
+        /// <summary>
+        /// Create a new work item
+        /// </summary>
+        /// <param name="wigStartInfo">Work item group start information</param>
+        /// <param name="workItemInfo">Work item info</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <returns>Returns a work item</returns>
+        public static WorkItem CreateWorkItem(
+            IWorkItemsGroup workItemsGroup,
+            WIGStartInfo wigStartInfo,
+            WorkItemInfo workItemInfo, 
+            WorkItemCallback callback)
+        {
+            return CreateWorkItem(
+                workItemsGroup,
+                wigStartInfo,
+                workItemInfo, 
+                callback, 
+                null);
+        }
+
+        /// <summary>
+        /// Create a new work item
+        /// </summary>
+        /// <param name="wigStartInfo">Work item group start information</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <returns>Returns a work item</returns>
+        public static WorkItem CreateWorkItem(
+            IWorkItemsGroup workItemsGroup,
+            WIGStartInfo wigStartInfo,
+            WorkItemCallback callback, 
+            object state)
+        {
+            ValidateCallback(callback);
+
+            WorkItemInfo workItemInfo = new WorkItemInfo();
+            workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+            workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+            workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
+            workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
+            workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+
+            WorkItem workItem = new WorkItem(
+                workItemsGroup,
+                workItemInfo,
+                callback, 
+                state);
+            return workItem;
+        }
+
+        /// <summary>
+        /// Create a new work item
+        /// </summary>
+        /// <param name="wigStartInfo">Work item group start information</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="workItemPriority">The work item priority</param>
+        /// <returns>Returns a work item</returns>
+        public static WorkItem CreateWorkItem(
+            IWorkItemsGroup workItemsGroup,
+            WIGStartInfo wigStartInfo,
+            WorkItemCallback callback, 
+            object state, 
+            WorkItemPriority workItemPriority)
+        {
+            ValidateCallback(callback);
+
+            WorkItemInfo workItemInfo = new WorkItemInfo();
+            workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+            workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+            workItemInfo.PostExecuteWorkItemCallback = wigStartInfo.PostExecuteWorkItemCallback;
+            workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
+            workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+            workItemInfo.WorkItemPriority = workItemPriority;
+
+            WorkItem workItem = new WorkItem(
+                workItemsGroup,
+                workItemInfo,
+                callback, 
+                state);
+
+            return workItem;
+        }
+
+        /// <summary>
+        /// Create a new work item
+        /// </summary>
+        /// <param name="wigStartInfo">Work item group start information</param>
+        /// <param name="workItemInfo">Work item information</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <returns>Returns a work item</returns>
+        public static WorkItem CreateWorkItem(
+            IWorkItemsGroup workItemsGroup,
+            WIGStartInfo wigStartInfo,
+            WorkItemInfo workItemInfo, 
+            WorkItemCallback callback, 
+            object state)
+        {
+            ValidateCallback(callback);
+            ValidateCallback(workItemInfo.PostExecuteWorkItemCallback);
+
+            WorkItem workItem = new WorkItem(
+                workItemsGroup,
+                new WorkItemInfo(workItemInfo),
+                callback, 
+                state);
+
+            return workItem;
+        }
+
+        /// <summary>
+        /// Create a new work item
+        /// </summary>
+        /// <param name="wigStartInfo">Work item group start information</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <returns>Returns a work item</returns>
+        public static WorkItem CreateWorkItem(
+            IWorkItemsGroup workItemsGroup,
+            WIGStartInfo wigStartInfo,
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback)
+        {
+            ValidateCallback(callback);
+            ValidateCallback(postExecuteWorkItemCallback);
+
+            WorkItemInfo workItemInfo = new WorkItemInfo();
+            workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+            workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+            workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
+            workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
+            workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+
+            WorkItem workItem = new WorkItem(
+                workItemsGroup,
+                workItemInfo,
+                callback, 
+                state);
+
+            return workItem;
+        }
+
+        /// <summary>
+        /// Create a new work item
+        /// </summary>
+        /// <param name="wigStartInfo">Work item group start information</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <param name="workItemPriority">The work item priority</param>
+        /// <returns>Returns a work item</returns>
+        public static WorkItem CreateWorkItem(
+            IWorkItemsGroup workItemsGroup,
+            WIGStartInfo wigStartInfo,
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+            WorkItemPriority workItemPriority)
+        {
+            ValidateCallback(callback);
+            ValidateCallback(postExecuteWorkItemCallback);
+
+            WorkItemInfo workItemInfo = new WorkItemInfo();
+            workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+            workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+            workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
+            workItemInfo.CallToPostExecute = wigStartInfo.CallToPostExecute;
+            workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+            workItemInfo.WorkItemPriority = workItemPriority;
+
+            WorkItem workItem = new WorkItem(
+                workItemsGroup,
+                workItemInfo,
+                callback, 
+                state);
+
+            return workItem;
+        }
+
+        /// <summary>
+        /// Create a new work item
+        /// </summary>
+        /// <param name="wigStartInfo">Work item group start information</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
+        /// <returns>Returns a work item</returns>
+        public static WorkItem CreateWorkItem(
+            IWorkItemsGroup workItemsGroup,
+            WIGStartInfo wigStartInfo,
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+            CallToPostExecute callToPostExecute)
+        {
+            ValidateCallback(callback);
+            ValidateCallback(postExecuteWorkItemCallback);
+
+            WorkItemInfo workItemInfo = new WorkItemInfo();
+            workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+            workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+            workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
+            workItemInfo.CallToPostExecute = callToPostExecute;
+            workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+
+            WorkItem workItem = new WorkItem(
+                workItemsGroup,
+                workItemInfo,
+                callback, 
+                state);
+
+            return workItem;
+        }
+
+        /// <summary>
+        /// Create a new work item
+        /// </summary>
+        /// <param name="wigStartInfo">Work item group start information</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
+        /// <param name="workItemPriority">The work item priority</param>
+        /// <returns>Returns a work item</returns>
+        public static WorkItem CreateWorkItem(
+            IWorkItemsGroup workItemsGroup,
+            WIGStartInfo wigStartInfo,
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+            CallToPostExecute callToPostExecute,
+            WorkItemPriority workItemPriority)
+        {
+
+            ValidateCallback(callback);
+            ValidateCallback(postExecuteWorkItemCallback);
+
+            WorkItemInfo workItemInfo = new WorkItemInfo();
+            workItemInfo.UseCallerCallContext = wigStartInfo.UseCallerCallContext;
+            workItemInfo.UseCallerHttpContext = wigStartInfo.UseCallerHttpContext;
+            workItemInfo.PostExecuteWorkItemCallback = postExecuteWorkItemCallback;
+            workItemInfo.CallToPostExecute = callToPostExecute;
+            workItemInfo.WorkItemPriority = workItemPriority;
+            workItemInfo.DisposeOfStateObjects = wigStartInfo.DisposeOfStateObjects;
+
+            WorkItem workItem = new WorkItem(
+                workItemsGroup,
+                workItemInfo,
+                callback, 
+                state);
+            
+            return workItem;
+        }
+
+        private static void ValidateCallback(Delegate callback)
+        {
+            if(callback.GetInvocationList().Length > 1)
+            {
+                throw new NotSupportedException("SmartThreadPool doesn't support delegates chains");
+            }
+        }
+    }
+
+    #endregion
+}

+ 102 - 0
ThirdParty/SmartThreadPool/WorkItemInfo.cs

@@ -0,0 +1,102 @@
+// Ami Bar
+// [email protected]
+
+namespace Amib.Threading
+{
+    #region WorkItemInfo class
+
+    /// <summary>
+    /// Summary description for WorkItemInfo.
+    /// </summary>
+    public class WorkItemInfo
+    {
+        /// <summary>
+        /// Use the caller's security context
+        /// </summary>
+        private bool _useCallerCallContext;
+
+        /// <summary>
+        /// Use the caller's security context
+        /// </summary>
+        private bool _useCallerHttpContext;
+
+        /// <summary>
+        /// Dispose of the state object of a work item
+        /// </summary>
+        private bool _disposeOfStateObjects;
+
+        /// <summary>
+        /// The option to run the post execute
+        /// </summary>
+        private CallToPostExecute _callToPostExecute;
+
+        /// <summary>
+        /// A post execute callback to call when none is provided in 
+        /// the QueueWorkItem method.
+        /// </summary>
+        private PostExecuteWorkItemCallback _postExecuteWorkItemCallback;
+        
+        /// <summary>
+        /// The priority of the work item
+        /// </summary>
+        private WorkItemPriority _workItemPriority;
+
+        public WorkItemInfo()
+        {
+            _useCallerCallContext = SmartThreadPool.DefaultUseCallerCallContext;
+            _useCallerHttpContext = SmartThreadPool.DefaultUseCallerHttpContext;
+            _disposeOfStateObjects = SmartThreadPool.DefaultDisposeOfStateObjects;
+            _callToPostExecute = SmartThreadPool.DefaultCallToPostExecute;
+            _postExecuteWorkItemCallback = SmartThreadPool.DefaultPostExecuteWorkItemCallback;
+            _workItemPriority = SmartThreadPool.DefaultWorkItemPriority;
+        }
+
+        public WorkItemInfo(WorkItemInfo workItemInfo)
+        {
+            _useCallerCallContext = workItemInfo._useCallerCallContext;
+            _useCallerHttpContext = workItemInfo._useCallerHttpContext;
+            _disposeOfStateObjects = workItemInfo._disposeOfStateObjects;
+            _callToPostExecute = workItemInfo._callToPostExecute;
+            _postExecuteWorkItemCallback = workItemInfo._postExecuteWorkItemCallback;
+            _workItemPriority = workItemInfo._workItemPriority;
+        }
+
+        public bool UseCallerCallContext
+        {
+            get { return _useCallerCallContext; }
+            set { _useCallerCallContext = value; }
+        }
+
+        public bool UseCallerHttpContext
+        {
+            get { return _useCallerHttpContext; }
+            set { _useCallerHttpContext = value; }
+        }
+
+        public bool DisposeOfStateObjects
+        {
+            get { return _disposeOfStateObjects; }
+            set { _disposeOfStateObjects = value; }
+        }
+
+        public CallToPostExecute CallToPostExecute
+        {
+            get { return _callToPostExecute; }
+            set { _callToPostExecute = value; }
+        }
+
+        public PostExecuteWorkItemCallback PostExecuteWorkItemCallback
+        {
+            get { return _postExecuteWorkItemCallback; }
+            set { _postExecuteWorkItemCallback = value; }
+        }
+
+        public WorkItemPriority WorkItemPriority
+        {
+            get { return _workItemPriority; }
+            set { _workItemPriority = value; }
+        }
+    }
+
+    #endregion
+}

+ 512 - 0
ThirdParty/SmartThreadPool/WorkItemsGroup.cs

@@ -0,0 +1,512 @@
+// Ami Bar
+// [email protected]
+
+using System;
+using System.Threading;
+using System.Runtime.CompilerServices;
+using System.Diagnostics;
+
+namespace Amib.Threading.Internal
+{
+    #region WorkItemsGroup class 
+
+    /// <summary>
+    /// Summary description for WorkItemsGroup.
+    /// </summary>
+    public class WorkItemsGroup : IWorkItemsGroup
+    {
+        #region Private members
+
+        private object _lock = new object();
+        /// <summary>
+        /// Contains the name of this instance of SmartThreadPool.
+        /// Can be changed by the user.
+        /// </summary>
+        private string _name = "WorkItemsGroup";
+
+        /// <summary>
+        /// A reference to the SmartThreadPool instance that created this 
+        /// WorkItemsGroup.
+        /// </summary>
+        private SmartThreadPool _stp;
+
+        /// <summary>
+        /// The OnIdle event
+        /// </summary>
+        private event WorkItemsGroupIdleHandler _onIdle;
+
+        /// <summary>
+        /// Defines how many work items of this WorkItemsGroup can run at once.
+        /// </summary>
+        private int _concurrency;
+
+        /// <summary>
+        /// Priority queue to hold work items before they are passed 
+        /// to the SmartThreadPool.
+        /// </summary>
+        private PriorityQueue _workItemsQueue;
+
+        /// <summary>
+        /// Indicate how many work items are waiting in the SmartThreadPool
+        /// queue.
+        /// This value is used to apply the concurrency.
+        /// </summary>
+        private int _workItemsInStpQueue;
+
+        /// <summary>
+        /// Indicate how many work items are currently running in the SmartThreadPool.
+        /// This value is used with the Cancel, to calculate if we can send new 
+        /// work items to the STP.
+        /// </summary>
+        private int _workItemsExecutingInStp = 0;
+
+        /// <summary>
+        /// WorkItemsGroup start information
+        /// </summary>
+        private WIGStartInfo _workItemsGroupStartInfo;
+
+        /// <summary>
+        /// Signaled when all of the WorkItemsGroup's work item completed.
+        /// </summary>
+        private ManualResetEvent _isIdleWaitHandle = new ManualResetEvent(true);
+
+        /// <summary>
+        /// A common object for all the work items that this work items group
+        /// generate so we can mark them to cancel in O(1)
+        /// </summary>
+        private CanceledWorkItemsGroup _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
+
+        #endregion 
+
+        #region Construction
+
+        public WorkItemsGroup(
+            SmartThreadPool stp, 
+            int concurrency, 
+            WIGStartInfo wigStartInfo)
+        {
+            if (concurrency <= 0)
+            {
+                throw new ArgumentOutOfRangeException("concurrency", concurrency, "concurrency must be greater than zero");
+            }
+            _stp = stp;
+            _concurrency = concurrency;
+            _workItemsGroupStartInfo = new WIGStartInfo(wigStartInfo);
+            _workItemsQueue = new PriorityQueue();
+
+            // The _workItemsInStpQueue gets the number of currently executing work items,
+            // because once a work item is executing, it cannot be cancelled.
+            _workItemsInStpQueue = _workItemsExecutingInStp;
+        }
+
+        #endregion 
+
+        #region IWorkItemsGroup implementation
+
+        /// <summary>
+        /// Get/Set the name of the SmartThreadPool instance
+        /// </summary>
+        public string Name 
+        { 
+            get
+            {
+                return _name;
+            }
+
+            set
+            {
+                _name = value;
+            }
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemCallback callback)
+        {
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback);
+            EnqueueToSTPNextWorkItem(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="workItemPriority">The priority of the work item</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemCallback callback, WorkItemPriority workItemPriority)
+        {
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, workItemPriority);
+            EnqueueToSTPNextWorkItem(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="workItemInfo">Work item info</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback)
+        {
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback);
+            EnqueueToSTPNextWorkItem(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state)
+        {
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state);
+            EnqueueToSTPNextWorkItem(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="workItemPriority">The work item priority</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemCallback callback, object state, WorkItemPriority workItemPriority)
+        {
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, workItemPriority);
+            EnqueueToSTPNextWorkItem(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="workItemInfo">Work item information</param>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(WorkItemInfo workItemInfo, WorkItemCallback callback, object state)
+        {
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, workItemInfo, callback, state);
+            EnqueueToSTPNextWorkItem(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback)
+        {
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback);
+            EnqueueToSTPNextWorkItem(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <param name="workItemPriority">The work item priority</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+            WorkItemPriority workItemPriority)
+        {
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, workItemPriority);
+            EnqueueToSTPNextWorkItem(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+            CallToPostExecute callToPostExecute)
+        {
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute);
+            EnqueueToSTPNextWorkItem(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Queue a work item
+        /// </summary>
+        /// <param name="callback">A callback to execute</param>
+        /// <param name="state">
+        /// The context object of the work item. Used for passing arguments to the work item. 
+        /// </param>
+        /// <param name="postExecuteWorkItemCallback">
+        /// A delegate to call after the callback completion
+        /// </param>
+        /// <param name="callToPostExecute">Indicates on which cases to call to the post execute callback</param>
+        /// <param name="workItemPriority">The work item priority</param>
+        /// <returns>Returns a work item result</returns>
+        public IWorkItemResult QueueWorkItem(
+            WorkItemCallback callback, 
+            object state,
+            PostExecuteWorkItemCallback postExecuteWorkItemCallback,
+            CallToPostExecute callToPostExecute,
+            WorkItemPriority workItemPriority)
+        {
+            WorkItem workItem = WorkItemFactory.CreateWorkItem(this, _workItemsGroupStartInfo, callback, state, postExecuteWorkItemCallback, callToPostExecute, workItemPriority);
+            EnqueueToSTPNextWorkItem(workItem);
+            return workItem.GetWorkItemResult();
+        }
+
+        /// <summary>
+        /// Wait for the thread pool to be idle
+        /// </summary>
+        public void WaitForIdle()
+        {
+            WaitForIdle(Timeout.Infinite);
+        }
+
+        /// <summary>
+        /// Wait for the thread pool to be idle
+        /// </summary>
+        public bool WaitForIdle(TimeSpan timeout)
+        {
+            return WaitForIdle((int)timeout.TotalMilliseconds);
+        }
+
+        /// <summary>
+        /// Wait for the thread pool to be idle
+        /// </summary>
+        public bool WaitForIdle(int millisecondsTimeout)
+        {
+            _stp.ValidateWorkItemsGroupWaitForIdle(this);
+            return _isIdleWaitHandle.WaitOne(millisecondsTimeout, false);
+        }
+
+        public int WaitingCallbacks
+        {
+            get
+            {
+                return _workItemsQueue.Count;
+            }
+        }
+
+        public event WorkItemsGroupIdleHandler OnIdle
+        {
+            add
+            {
+                _onIdle += value;
+            }
+            remove
+            {
+                _onIdle -= value;
+            }
+        }
+
+        public void Cancel()
+        {
+            lock(_lock)
+            {
+                _canceledWorkItemsGroup.IsCanceled = true;
+                _workItemsQueue.Clear();
+                _workItemsInStpQueue = 0;
+                _canceledWorkItemsGroup = new CanceledWorkItemsGroup();
+            }
+        }
+
+        public void Start()
+        {
+            lock (this)
+            {
+                if (!_workItemsGroupStartInfo.StartSuspended)
+                {
+                    return;
+                }
+                _workItemsGroupStartInfo.StartSuspended = false;
+            }
+            
+            for(int i = 0; i < _concurrency; ++i)
+            {
+                EnqueueToSTPNextWorkItem(null, false);
+            }
+        }
+
+        #endregion 
+
+        #region Private methods
+
+        private void RegisterToWorkItemCompletion(IWorkItemResult wir)
+        {
+            IInternalWorkItemResult iwir = wir as IInternalWorkItemResult;
+            iwir.OnWorkItemStarted += new WorkItemStateCallback(OnWorkItemStartedCallback);
+            iwir.OnWorkItemCompleted += new WorkItemStateCallback(OnWorkItemCompletedCallback);
+        }
+
+        public void OnSTPIsStarting()
+        {
+            lock (this)
+            {
+                if (_workItemsGroupStartInfo.StartSuspended)
+                {
+                    return;
+                }
+            }
+            
+            for(int i = 0; i < _concurrency; ++i)
+            {
+                EnqueueToSTPNextWorkItem(null, false);
+            }
+        }
+
+        private object FireOnIdle(object state)
+        {
+            FireOnIdleImpl(_onIdle);
+            return null;
+        }
+
+        [MethodImpl(MethodImplOptions.NoInlining)]
+        private void FireOnIdleImpl(WorkItemsGroupIdleHandler onIdle)
+        {
+            if(null == onIdle)
+            {
+                return;
+            }
+
+            Delegate[] delegates = onIdle.GetInvocationList();
+            foreach(WorkItemsGroupIdleHandler eh in delegates)
+            {
+                try
+                {
+                    eh(this);
+                }
+                    // Ignore exceptions
+                catch{} 
+            }
+        }
+
+        private void OnWorkItemStartedCallback(WorkItem workItem)
+        {
+            lock(_lock)
+            {
+                ++_workItemsExecutingInStp;
+            }
+        }
+
+        private void OnWorkItemCompletedCallback(WorkItem workItem)
+        {
+            EnqueueToSTPNextWorkItem(null, true);
+        }
+
+        private void EnqueueToSTPNextWorkItem(WorkItem workItem)
+        {
+            EnqueueToSTPNextWorkItem(workItem, false);
+        }
+
+        private void EnqueueToSTPNextWorkItem(WorkItem workItem, bool decrementWorkItemsInStpQueue)
+        {
+            lock(_lock)
+            {
+                // Got here from OnWorkItemCompletedCallback()
+                if (decrementWorkItemsInStpQueue)
+                {
+                    --_workItemsInStpQueue;
+
+                    if(_workItemsInStpQueue < 0)
+                    {
+                        _workItemsInStpQueue = 0;
+                    }
+
+                    --_workItemsExecutingInStp;
+
+                    if(_workItemsExecutingInStp < 0)
+                    {
+                        _workItemsExecutingInStp = 0;
+                    }
+                }
+
+                // If the work item is not null then enqueue it
+                if (null != workItem)
+                {
+                    workItem.CanceledWorkItemsGroup = _canceledWorkItemsGroup;
+
+                    RegisterToWorkItemCompletion(workItem.GetWorkItemResult());
+                    _workItemsQueue.Enqueue(workItem);
+                    //_stp.IncrementWorkItemsCount();
+
+                    if ((1 == _workItemsQueue.Count) && 
+                        (0 == _workItemsInStpQueue))
+                    {
+                        _stp.RegisterWorkItemsGroup(this);
+                        Trace.WriteLine("WorkItemsGroup " + Name + " is NOT idle");
+                        _isIdleWaitHandle.Reset();
+                    }
+                }
+
+                // If the work items queue of the group is empty than quit
+                if (0 == _workItemsQueue.Count)
+                {
+                    if (0 == _workItemsInStpQueue)
+                    {
+                        _stp.UnregisterWorkItemsGroup(this);
+                        Trace.WriteLine("WorkItemsGroup " + Name + " is idle");
+                        _isIdleWaitHandle.Set();
+                        _stp.QueueWorkItem(new WorkItemCallback(this.FireOnIdle));
+                    }
+                    return;
+                }
+
+                if (!_workItemsGroupStartInfo.StartSuspended)
+                {
+                    if (_workItemsInStpQueue < _concurrency)
+                    {
+                        WorkItem nextWorkItem = _workItemsQueue.Dequeue() as WorkItem;
+                        _stp.Enqueue(nextWorkItem, true);
+                        ++_workItemsInStpQueue;
+                    }
+                }
+            }
+        }
+
+        #endregion
+    }
+
+    #endregion
+}

+ 600 - 0
ThirdParty/SmartThreadPool/WorkItemsQueue.cs

@@ -0,0 +1,600 @@
+// Ami Bar
+// [email protected]
+
+using System;
+using System.Threading;
+
+namespace Amib.Threading.Internal
+{
+    #region WorkItemsQueue class
+
+    /// <summary>
+    /// WorkItemsQueue class.
+    /// </summary>
+    public class WorkItemsQueue : IDisposable
+    {
+        #region Member variables
+
+        /// <summary>
+        /// Waiters queue (implemented as stack).
+        /// </summary>
+        private WaiterEntry _headWaiterEntry = new WaiterEntry();
+
+        /// <summary>
+        /// Waiters count
+        /// </summary>
+        private int _waitersCount = 0;
+
+        /// <summary>
+        /// Work items queue
+        /// </summary>
+        private PriorityQueue _workItems = new PriorityQueue();
+
+        /// <summary>
+        /// Indicate that work items are allowed to be queued
+        /// </summary>
+        private bool _isWorkItemsQueueActive = true;
+
+        /// <summary>
+        /// Each thread in the thread pool keeps its own waiter entry.
+        /// </summary>
+        [ThreadStatic]
+        private static WaiterEntry _waiterEntry;
+
+        /// <summary>
+        /// A flag that indicates if the WorkItemsQueue has been disposed.
+        /// </summary>
+        private bool _isDisposed = false;
+
+        #endregion
+
+        #region Public properties
+
+        /// <summary>
+        /// Returns the current number of work items in the queue
+        /// </summary>
+        public int Count
+        {
+            get
+            {
+                lock(this)
+                {
+                    ValidateNotDisposed();
+                    return _workItems.Count;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Returns the current number of waiters
+        /// </summary>
+        public int WaitersCount
+        {
+            get
+            {
+                lock(this)
+                {
+                    ValidateNotDisposed();
+                    return _waitersCount;
+                }
+            }
+        }
+
+
+        #endregion
+
+        #region Public methods
+
+        /// <summary>
+        /// Enqueue a work item to the queue.
+        /// </summary>
+        public bool EnqueueWorkItem(WorkItem workItem)
+        {
+            // A work item cannot be null, since null is used in the
+            // WaitForWorkItem() method to indicate timeout or cancel
+            if (null == workItem)
+            {
+                throw new ArgumentNullException("workItem" , "workItem cannot be null");
+            }
+
+            bool enqueue = true;
+
+            // First check if there is a waiter waiting for work item. During 
+            // the check, timed out waiters are ignored. If there is no 
+            // waiter then the work item is queued.
+            lock(this)
+            {
+                ValidateNotDisposed();
+
+                if (!_isWorkItemsQueueActive)
+                {
+                    return false;
+                }
+
+                while(_waitersCount > 0)
+                {
+                    // Dequeue a waiter.
+                    WaiterEntry waiterEntry = PopWaiter();
+
+                    // Signal the waiter. On success break the loop
+                    if (waiterEntry.Signal(workItem))
+                    {
+                        enqueue = false;
+                        break;
+                    }
+                }
+
+                if (enqueue)
+                {
+                    // Enqueue the work item
+                    _workItems.Enqueue(workItem);
+                }
+            }
+            return true;
+        }
+
+
+        /// <summary>
+        /// Waits for a work item or exits on timeout or cancel
+        /// </summary>
+        /// <param name="millisecondsTimeout">Timeout in milliseconds</param>
+        /// <param name="cancelEvent">Cancel wait handle</param>
+        /// <returns>Returns true if the resource was granted</returns>
+        public WorkItem DequeueWorkItem(
+            int millisecondsTimeout, 
+            WaitHandle cancelEvent)
+        {
+            /// This method cause the caller to wait for a work item.
+            /// If there is at least one waiting work item then the 
+            /// method returns immidiately with true.
+            /// 
+            /// If there are no waiting work items then the caller 
+            /// is queued between other waiters for a work item to arrive.
+            /// 
+            /// If a work item didn't come within millisecondsTimeout or 
+            /// the user canceled the wait by signaling the cancelEvent 
+            /// then the method returns false to indicate that the caller 
+            /// didn't get a work item.
+
+            WaiterEntry waiterEntry = null;
+            WorkItem workItem = null;
+
+            lock(this)
+            {
+                ValidateNotDisposed();
+
+                // If there are waiting work items then take one and return.
+                if (_workItems.Count > 0)
+                {
+                    workItem = _workItems.Dequeue() as WorkItem;
+                    return workItem;
+                }
+                    // No waiting work items ...
+                else
+                {
+                    // Get the wait entry for the waiters queue
+                    waiterEntry = GetThreadWaiterEntry();
+
+                    // Put the waiter with the other waiters
+                    PushWaiter(waiterEntry);
+                }
+            }
+
+            // Prepare array of wait handle for the WaitHandle.WaitAny()
+            WaitHandle [] waitHandles = new WaitHandle [] { 
+                                                                waiterEntry.WaitHandle, 
+                                                                cancelEvent };
+
+            // Wait for an available resource, cancel event, or timeout.
+
+            // During the wait we are supposes to exit the synchronization 
+            // domain. (Placing true as the third argument of the WaitAny())
+            // It just doesn't work, I don't know why, so I have lock(this) 
+            // statments insted of one.
+
+            int index = WaitHandle.WaitAny(
+                waitHandles,
+                millisecondsTimeout, 
+                true);
+
+            lock(this)
+            {
+                // success is true if it got a work item.
+                bool success = (0 == index);
+
+                // The timeout variable is used only for readability.
+                // (We treat cancel as timeout)
+                bool timeout = !success;
+
+                // On timeout update the waiterEntry that it is timed out
+                if (timeout)
+                {
+                    // The Timeout() fails if the waiter has already been signaled
+                    timeout = waiterEntry.Timeout();
+
+                    // On timeout remove the waiter from the queue.
+                    // Note that the complexity is O(1).
+                    if(timeout)
+                    {
+                        RemoveWaiter(waiterEntry, false);
+                    }
+
+                    // Again readability
+                    success = !timeout;
+                }
+
+                // On success return the work item
+                if (success)
+                {
+                    workItem = waiterEntry.WorkItem;
+
+                    if (null == workItem)
+                    {
+                        workItem = _workItems.Dequeue() as WorkItem;
+                    }
+                }
+            }
+            // On failure return null.
+            return workItem;
+        }
+
+        /// <summary>
+        /// Cleanup the work items queue, hence no more work 
+        /// items are allowed to be queue
+        /// </summary>
+        protected virtual void Cleanup()
+        {
+            lock(this)
+            {
+                // Deactivate only once
+                if (!_isWorkItemsQueueActive)
+                {
+                    return;
+                }
+
+                // Don't queue more work items
+                _isWorkItemsQueueActive = false;
+
+                foreach(WorkItem workItem in _workItems)
+                {
+                    workItem.DisposeOfState();
+                }
+
+                // Clear the work items that are already queued
+                _workItems.Clear();
+
+                // Note: 
+                // I don't iterate over the queue and dispose of work items's states, 
+                // since if a work item has a state object that is still in use in the 
+                // application then I must not dispose it.
+
+                // Tell the waiters that they were timed out.
+                // It won't signal them to exit, but to ignore their
+                // next work item.
+                while(_waitersCount > 0)
+                {
+                    WaiterEntry waiterEntry = PopWaiter();
+                    waiterEntry.Timeout();
+                }
+            }
+        }
+
+        #endregion
+
+        #region Private methods
+
+        /// <summary>
+        /// Returns the WaiterEntry of the current thread
+        /// </summary>
+        /// <returns></returns>
+        /// In order to avoid creation and destuction of WaiterEntry
+        /// objects each thread has its own WaiterEntry object.
+        private WaiterEntry GetThreadWaiterEntry()
+        {
+            if (null == _waiterEntry)
+            {
+                _waiterEntry = new WaiterEntry();
+            }
+            _waiterEntry.Reset();
+            return _waiterEntry;
+        }
+
+        #region Waiters stack methods
+
+        /// <summary>
+        /// Push a new waiter into the waiter's stack
+        /// </summary>
+        /// <param name="newWaiterEntry">A waiter to put in the stack</param>
+        public void PushWaiter(WaiterEntry newWaiterEntry)
+        {
+            // Remove the waiter if it is already in the stack and 
+            // update waiter's count as needed
+            RemoveWaiter(newWaiterEntry, false);
+
+            // If the stack is empty then newWaiterEntry is the new head of the stack 
+            if (null == _headWaiterEntry._nextWaiterEntry)
+            {
+                _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
+                newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
+
+            }
+            // If the stack is not empty then put newWaiterEntry as the new head 
+            // of the stack.
+            else
+            {
+                // Save the old first waiter entry
+                WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
+
+                // Update the links
+                _headWaiterEntry._nextWaiterEntry = newWaiterEntry;
+                newWaiterEntry._nextWaiterEntry = oldFirstWaiterEntry;
+                newWaiterEntry._prevWaiterEntry = _headWaiterEntry;
+                oldFirstWaiterEntry._prevWaiterEntry = newWaiterEntry;
+            }
+
+            // Increment the number of waiters
+            ++_waitersCount;
+        }
+
+        /// <summary>
+        /// Pop a waiter from the waiter's stack
+        /// </summary>
+        /// <returns>Returns the first waiter in the stack</returns>
+        private WaiterEntry PopWaiter()
+        {
+            // Store the current stack head
+            WaiterEntry oldFirstWaiterEntry = _headWaiterEntry._nextWaiterEntry;
+
+            // Store the new stack head
+            WaiterEntry newHeadWaiterEntry = oldFirstWaiterEntry._nextWaiterEntry;
+
+            // Update the old stack head list links and decrement the number
+            // waiters.
+            RemoveWaiter(oldFirstWaiterEntry, true);
+
+            // Update the new stack head
+            _headWaiterEntry._nextWaiterEntry = newHeadWaiterEntry;
+            if (null != newHeadWaiterEntry)
+            {
+                newHeadWaiterEntry._prevWaiterEntry = _headWaiterEntry;
+            }
+
+            // Return the old stack head
+            return oldFirstWaiterEntry;
+        }
+
+        /// <summary>
+        /// Remove a waiter from the stack
+        /// </summary>
+        /// <param name="waiterEntry">A waiter entry to remove</param>
+        /// <param name="popDecrement">If true the waiter count is always decremented</param>
+        private void RemoveWaiter(WaiterEntry waiterEntry, bool popDecrement)
+        {
+            // Store the prev entry in the list
+            WaiterEntry prevWaiterEntry = waiterEntry._prevWaiterEntry;
+
+            // Store the next entry in the list
+            WaiterEntry nextWaiterEntry = waiterEntry._nextWaiterEntry;
+
+            // A flag to indicate if we need to decrement the waiters count.
+            // If we got here from PopWaiter then we must decrement.
+            // If we got here from PushWaiter then we decrement only if
+            // the waiter was already in the stack.
+            bool decrementCounter = popDecrement;
+
+            // Null the waiter's entry links
+            waiterEntry._prevWaiterEntry = null;
+            waiterEntry._nextWaiterEntry = null;
+
+            // If the waiter entry had a prev link then update it.
+            // It also means that the waiter is already in the list and we
+            // need to decrement the waiters count.
+            if (null != prevWaiterEntry)
+            {
+                prevWaiterEntry._nextWaiterEntry = nextWaiterEntry;
+                decrementCounter = true;
+            }
+
+            // If the waiter entry had a next link then update it.
+            // It also means that the waiter is already in the list and we
+            // need to decrement the waiters count.
+            if (null != nextWaiterEntry)
+            {
+                nextWaiterEntry._prevWaiterEntry = prevWaiterEntry;
+                decrementCounter = true;
+            }
+
+            // Decrement the waiters count if needed
+            if (decrementCounter)
+            {
+                --_waitersCount;
+            }
+        }
+
+        #endregion
+
+        #endregion
+
+        #region WaiterEntry class 
+
+        // A waiter entry in the _waiters queue.
+        public class WaiterEntry : IDisposable
+        {
+            #region Member variables
+
+            /// <summary>
+            /// Event to signal the waiter that it got the work item.
+            /// </summary>
+            private AutoResetEvent _waitHandle = new AutoResetEvent(false);
+
+            /// <summary>
+            /// Flag to know if this waiter already quited from the queue 
+            /// because of a timeout.
+            /// </summary>
+            private bool _isTimedout = false;
+
+            /// <summary>
+            /// Flag to know if the waiter was signaled and got a work item. 
+            /// </summary>
+            private bool _isSignaled = false;
+
+            /// <summary>
+            /// A work item that passed directly to the waiter withou going 
+            /// through the queue
+            /// </summary>
+            private WorkItem _workItem = null;
+
+            private bool _isDisposed = false;
+
+            // Linked list members
+            internal WaiterEntry _nextWaiterEntry = null;
+            internal WaiterEntry _prevWaiterEntry = null;
+
+            #endregion
+
+            #region Construction
+
+            public WaiterEntry()
+            {
+                Reset();
+            }
+                        
+            #endregion
+
+            #region Public methods
+
+            public WaitHandle WaitHandle
+            {
+                get { return _waitHandle; }
+            }
+
+            public WorkItem WorkItem
+            {
+                get
+                {
+                    lock(this)
+                    {
+                        return _workItem;
+                    }
+                }
+            }
+
+            /// <summary>
+            /// Signal the waiter that it got a work item.
+            /// </summary>
+            /// <returns>Return true on success</returns>
+            /// The method fails if Timeout() preceded its call
+            public bool Signal(WorkItem workItem)
+            {
+                lock(this)
+                {
+                    if (!_isTimedout)
+                    {
+                        _workItem = workItem;
+                        _isSignaled = true;
+                        _waitHandle.Set();
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            /// <summary>
+            /// Mark the wait entry that it has been timed out
+            /// </summary>
+            /// <returns>Return true on success</returns>
+            /// The method fails if Signal() preceded its call
+            public bool Timeout()
+            {
+                lock(this)
+                {
+                    // Time out can happen only if the waiter wasn't marked as
+                    // signaled
+                    if (!_isSignaled)
+                    {
+                        // We don't remove the waiter from the queue, the DequeueWorkItem 
+                        // method skips _waiters that were timed out.
+                        _isTimedout = true;
+                        return true;
+                    }
+                }
+                return false;
+            }
+
+            /// <summary>
+            /// Reset the wait entry so it can be used again
+            /// </summary>
+            public void Reset()
+            {
+                _workItem = null;
+                _isTimedout = false;
+                _isSignaled = false;
+                _waitHandle.Reset();
+            }
+
+            /// <summary>
+            /// Free resources
+            /// </summary>
+            public void Close()
+            {
+                if (null != _waitHandle)
+                {
+                    _waitHandle.Close();
+                    _waitHandle = null;
+                }
+            }
+
+            #endregion
+
+            #region IDisposable Members
+
+            public void Dispose()
+            {
+                if (!_isDisposed)
+                {
+                    Close();
+                    _isDisposed = true;
+                }
+            }
+
+            ~WaiterEntry()
+            {
+                Dispose();
+            }
+
+            #endregion
+        }
+
+        #endregion
+
+        #region IDisposable Members
+
+        public void Dispose()
+        {
+            if (!_isDisposed)
+            {
+                Cleanup();
+                _isDisposed = true;
+                GC.SuppressFinalize(this);
+            }
+        }
+
+        ~WorkItemsQueue()
+        {
+            Cleanup();
+        }
+
+        private void ValidateNotDisposed()
+        {
+            if(_isDisposed)
+            {
+                throw new ObjectDisposedException(GetType().ToString(), "The SmartThreadPool has been shutdown");
+            }
+        }
+
+        #endregion
+    }
+
+    #endregion
+}
+

+ 22 - 0
ThirdPartyLicenses/SmartThreadPool.txt

@@ -0,0 +1,22 @@
+Microsoft Public License (Ms-PL)
+
+This license governs use of the accompanying software. If you use the software, you
+accept this license. If you do not accept the license, do not use the software.
+
+1. Definitions
+The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
+same meaning here as under U.S. copyright law.
+A "contribution" is the original software, or any additions or changes to the software.
+A "contributor" is any person that distributes its contribution under this license.
+"Licensed patents" are a contributor's patent claims that read directly on its contribution.
+
+2. Grant of Rights
+(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create.
+(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software.
+
+3. Conditions and Limitations
+(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks.
+(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically.
+(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software.
+(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license.
+(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement.

+ 37 - 0
bin/OpenSim.ini.example

@@ -535,3 +535,40 @@ Password = "password"
 ImportOnStartup = false
 Autosave = false
 AutoSavePeriod = 15 ; Number of minutes between autosave backups
+
+
+[XEngine]
+; How many threads to keep alive even if nothing is happening
+MinThreads = 2
+; How many threads to start at maximum load
+MaxThreads = 100
+; Time a thread must be idle (in seconds) before it dies
+IdleTimeout = 60
+; Thread priority ("Lowest", "BelowNormal", "Normal", "AboveNormal", "Highest")
+Priority = "BelowNormal"
+; Maximum number of events to queue for a script (excluding timers)
+MaxScriptEventQueue = 300
+; Stack size per thread created
+ThreadStackSize = 262144
+; Rate to poll for asynchronous command replies (ms)
+AsyncLLCommandLoopms = 50
+; Save the source of all compiled scripts
+WriteScriptSourceToDebugFile = false
+; Default language for scripts
+DefaultCompileLanguage = lsl
+; List of allowed languages (lsl,vb,js,cs)
+AllowedCompilers = lsl
+; Compile debug info (line numbers) into the script assemblies
+CompileWithDebugInformation = true
+; Allow the use of os* functions (some are dangerous)
+AllowOSFunctions = false
+; Interval (s) between background save of script states
+SaveInterval = 120
+; Interval (s) between maintenance runs (0 = disable)
+MaintenanceInterval = 10
+; Time a script can spend in an event handler before it is interrupted
+EventLimit = 30
+; If a script overruns it's event limit, kill the script?
+KillTimedOutScripts = false
+; Allow OS console command functionality (VERY DANGEROUS!!)
+AllowosConsoleCommand = false

+ 94 - 0
prebuild.xml

@@ -1345,6 +1345,63 @@
       </Files>
     </Project>
 
+    <Project name="OpenSim.Region.ScriptEngine.XEngine.Script" path="OpenSim/Region/ScriptEngine/XEngine/Script" type="Library">
+      <Configuration name="Debug">
+        <Options>
+          <OutputPath>../../../../../bin/</OutputPath>
+        </Options>
+      </Configuration>
+      <Configuration name="Release">
+        <Options>
+          <OutputPath>../../../../../bin/</OutputPath>
+        </Options>
+      </Configuration>
+
+      <ReferencePath>../../../../../bin/</ReferencePath>      
+      <Reference name="System" localCopy="false"/>
+      <Reference name="System.Data" localCopy="false"/>
+      <Reference name="System.Web" localCopy="false"/>
+      <Reference name="System.Xml" localCopy="false"/>
+      <Reference name="libsecondlife.dll"/>
+      <Reference name="OpenSim" />
+      <Reference name="OpenSim.Framework"/>
+      <Reference name="OpenSim.Framework.Communications"/>
+      <Reference name="OpenSim.Region.Environment" />
+      <Reference name="OpenSim.Framework.Console"/>
+      <Reference name="Axiom.MathLib.dll" localCopy="false"/>
+      <Reference name="Nini.dll" />
+      <Reference name="RAIL.dll"/>
+      <Reference name="Nini.dll" />
+      <Reference name="log4net"/>
+
+      <Files>
+        <Match pattern="*.cs" recurse="true"/>
+      </Files>
+    </Project>
+
+    <Project name="SmartThreadPool" path="ThirdParty/SmartThreadPool" type="Library">
+      <Configuration name="Debug">
+        <Options>
+          <OutputPath>../../bin/</OutputPath>          
+        </Options>
+      </Configuration>
+      <Configuration name="Release">
+        <Options>
+          <OutputPath>../../bin/</OutputPath>
+        </Options>
+      </Configuration>
+
+      <ReferencePath>../../bin/</ReferencePath>
+      <Reference name="System" localCopy="false"/>
+      <Reference name="System.Xml"/>
+      <Reference name="System.Data"/>
+      <Reference name="System.Web"/>
+      <Files>
+        <Match pattern="*.cs" recurse="false"/>
+      </Files>
+    </Project>
+
+
 
     <!-- OGS projects -->
 
@@ -1571,6 +1628,43 @@
       </Files>
     </Project>
 
+    <Project name="OpenSim.Region.ScriptEngine.XEngine" path="OpenSim/Region/ScriptEngine/XEngine" type="Library">
+      <Configuration name="Debug">
+        <Options>
+          <OutputPath>../../../../bin/ScriptEngines/</OutputPath>
+        </Options>
+      </Configuration>
+      <Configuration name="Release">
+        <Options>
+          <OutputPath>../../../../bin/ScriptEngines/</OutputPath>
+        </Options>
+      </Configuration>
+
+      <ReferencePath>../../../../bin/</ReferencePath>      
+      <Reference name="System" localCopy="false"/>
+      <Reference name="System.Data" localCopy="false"/>
+      <Reference name="System.Xml" localCopy="false"/>
+      <Reference name="System.Runtime.Remoting" localCopy="false"/>
+      <Reference name="libsecondlife.dll"/>
+      <Reference name="RAIL.dll"/>
+      <Reference name="OpenSim.Framework"/>
+      <Reference name="OpenSim.Framework.Console"/>
+      <Reference name="OpenSim.Framework.Communications"/>
+      <Reference name="OpenSim.Region.Environment" />
+      <Reference name="OpenSim.Region.ScriptEngine.XEngine.Script" />
+      <Reference name="Microsoft.JScript"/>
+      <Reference name="Axiom.MathLib.dll" localCopy="false"/>
+      <Reference name="Nini.dll" />
+      <Reference name="SmartThreadPool" />
+      <Reference name="log4net"/>
+
+      <Files>
+        <Match path="AsyncCommandPlugins" pattern="*.cs" recurse="false"/>
+        <Match pattern="*.cs" recurse="false"/>
+      </Files>
+    </Project>
+
+
 
     <Project name="OpenSim.Grid.ScriptServer" path="OpenSim/Grid/ScriptServer" type="Exe">
       <Configuration name="Debug">