aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment
diff options
context:
space:
mode:
authorMW2007-08-19 13:35:20 +0000
committerMW2007-08-19 13:35:20 +0000
commitc89db49f3cd3bbd60577eb5a1787ccf8dea930e3 (patch)
tree2b51b0d261724427933f543dd2f39ef8cd21127f /OpenSim/Region/Environment
parentCode comments on recent changes in EventQueueManager (diff)
downloadopensim-SC_OLD-c89db49f3cd3bbd60577eb5a1787ccf8dea930e3.zip
opensim-SC_OLD-c89db49f3cd3bbd60577eb5a1787ccf8dea930e3.tar.gz
opensim-SC_OLD-c89db49f3cd3bbd60577eb5a1787ccf8dea930e3.tar.bz2
opensim-SC_OLD-c89db49f3cd3bbd60577eb5a1787ccf8dea930e3.tar.xz
Sqlite datastore should now save the textures and extraparams data (used by sculpties) correctly. [Really need to add a ExtraParams field to the sqlite database though, but for now I have combined their data so that we don't lose backward compatibility, know a couple of people have been using the datastore already].
Now have a rough day/night cycle (the movement of the sun needs to be made smoother but for now it is better than we had I think). Added dalien's patch (issue 294) for saving and loading prims to a xml file (think he will be modifying these to be import/export functions and maybe writing a xml datastore for backups). Some preliminary work on task inventory (ie object's/prim's inventory). Added place holder data for AvatarProperties (ie a avatar's profile). Should we store this sort of data on the user server or have another server for it (a normal webserver should work). Added a few more method to IClientAPI. Sure there is something I'm forgeting.
Diffstat (limited to 'OpenSim/Region/Environment')
-rw-r--r--OpenSim/Region/Environment/Scenes/Scene.PacketHandlers.cs21
-rw-r--r--OpenSim/Region/Environment/Scenes/Scene.cs92
-rw-r--r--OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs24
-rw-r--r--OpenSim/Region/Environment/Scenes/SceneObjectPart.cs101
-rw-r--r--OpenSim/Region/Environment/Scenes/ScenePresence.cs3
5 files changed, 221 insertions, 20 deletions
diff --git a/OpenSim/Region/Environment/Scenes/Scene.PacketHandlers.cs b/OpenSim/Region/Environment/Scenes/Scene.PacketHandlers.cs
index f0f73b0..6b8ddc6 100644
--- a/OpenSim/Region/Environment/Scenes/Scene.PacketHandlers.cs
+++ b/OpenSim/Region/Environment/Scenes/Scene.PacketHandlers.cs
@@ -472,7 +472,7 @@ namespace OpenSim.Region.Environment.Scenes
472 hasPrim = ((SceneObjectGroup)ent).HasChildPrim(primLocalID); 472 hasPrim = ((SceneObjectGroup)ent).HasChildPrim(primLocalID);
473 if (hasPrim != false) 473 if (hasPrim != false)
474 { 474 {
475 ((SceneObjectGroup)ent).GetPartInventory(remoteClient, primLocalID); 475 ((SceneObjectGroup)ent).GetPartInventoryFileName(remoteClient, primLocalID);
476 break; 476 break;
477 } 477 }
478 } 478 }
@@ -758,6 +758,25 @@ namespace OpenSim.Region.Environment.Scenes
758 } 758 }
759 759
760 /// <summary> 760 /// <summary>
761 ///
762 /// </summary>
763 /// <param name="remoteClient"></param>
764 /// <param name="xferID"></param>
765 /// <param name="fileName"></param>
766 public void RequestXfer(IClientAPI remoteClient, ulong xferID, string fileName)
767 {
768 /*
769 foreach (EntityBase ent in Entities.Values)
770 {
771 if (ent is SceneObjectGroup)
772 {
773 ((SceneObjectGroup)ent).RequestInventoryFile(remoteClient, ((SceneObjectGroup)ent).LocalId, xferID);
774 break;
775 }
776 }*/
777 }
778
779 /// <summary>
761 /// temporary method to test out creating new inventory items 780 /// temporary method to test out creating new inventory items
762 /// </summary> 781 /// </summary>
763 /// <param name="remoteClient"></param> 782 /// <param name="remoteClient"></param>
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs
index 01e58c7..85479a7 100644
--- a/OpenSim/Region/Environment/Scenes/Scene.cs
+++ b/OpenSim/Region/Environment/Scenes/Scene.cs
@@ -29,6 +29,8 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Threading; 30using System.Threading;
31using System.Timers; 31using System.Timers;
32using System.IO;
33using System.Xml;
32using libsecondlife; 34using libsecondlife;
33using OpenSim.Framework; 35using OpenSim.Framework;
34using OpenSim.Framework.Communications; 36using OpenSim.Framework.Communications;
@@ -65,6 +67,10 @@ namespace OpenSim.Region.Environment.Scenes
65 private int storageCount; 67 private int storageCount;
66 private int terrainCheckCount; 68 private int terrainCheckCount;
67 private int landPrimCheckCount; 69 private int landPrimCheckCount;
70
71 private int m_timePhase = 24;
72 private int m_timeUpdateCount;
73
68 private Mutex updateLock; 74 private Mutex updateLock;
69 75
70 protected StorageManager storageManager; 76 protected StorageManager storageManager;
@@ -123,6 +129,11 @@ namespace OpenSim.Region.Environment.Scenes
123 get { return Prims; } 129 get { return Prims; }
124 } 130 }
125 131
132 public int TimePhase
133 {
134 get { return this.m_timePhase; }
135 }
136
126 #endregion 137 #endregion
127 138
128 #region Constructors 139 #region Constructors
@@ -301,6 +312,26 @@ namespace OpenSim.Region.Environment.Scenes
301 landPrimCheckCount = 0; 312 landPrimCheckCount = 0;
302 } 313 }
303 } 314 }
315
316 m_timeUpdateCount++;
317 if (m_timeUpdateCount > 600)
318 {
319 List<ScenePresence> Avatars = this.RequestAvatarList();
320 foreach (ScenePresence avatar in Avatars)
321 {
322 if (!avatar.childAgent)
323 {
324 //Console.WriteLine("sending time update " + timePhase + " from region " + m_regionHandle + " to avatar " + avatar.Firstname);
325 avatar.ControllingClient.SendViewerTime(m_timePhase);
326 }
327 }
328 m_timeUpdateCount = 0;
329 m_timePhase++;
330 if (m_timePhase > 94)
331 {
332 m_timePhase = 0;
333 }
334 }
304 } 335 }
305 catch (NotImplementedException) 336 catch (NotImplementedException)
306 { 337 {
@@ -538,7 +569,7 @@ namespace OpenSim.Region.Environment.Scenes
538 569
539 public void AddEntity(SceneObjectGroup sceneObject) 570 public void AddEntity(SceneObjectGroup sceneObject)
540 { 571 {
541 if(!Entities.ContainsKey(sceneObject.UUID)) 572 if (!Entities.ContainsKey(sceneObject.UUID))
542 { 573 {
543 Entities.Add(sceneObject.UUID, sceneObject); 574 Entities.Add(sceneObject.UUID, sceneObject);
544 } 575 }
@@ -563,6 +594,52 @@ namespace OpenSim.Region.Environment.Scenes
563 prim.OnPrimCountTainted += m_LandManager.setPrimsTainted; 594 prim.OnPrimCountTainted += m_LandManager.setPrimsTainted;
564 } 595 }
565 596
597 public void LoadPrimsFromXml(string fileName)
598 {
599 XmlDocument doc = new XmlDocument();
600 XmlNode rootNode;
601 int primCount = 0;
602 if (File.Exists(fileName))
603 {
604 XmlTextReader reader = new XmlTextReader(fileName);
605 reader.WhitespaceHandling = WhitespaceHandling.None;
606 doc.Load(reader);
607 reader.Close();
608 rootNode = doc.FirstChild;
609 foreach (XmlNode aPrimNode in rootNode.ChildNodes)
610 {
611 SceneObjectGroup obj = new SceneObjectGroup(this,
612 this.m_regionHandle, aPrimNode.OuterXml);
613 AddEntity(obj);
614 primCount++;
615 }
616 }
617 else
618 {
619 throw new Exception("Could not open file " + fileName + " for reading");
620 }
621 }
622
623 public void SavePrimsToXml(string fileName)
624 {
625 FileStream file = new FileStream(fileName, FileMode.Create);
626 StreamWriter stream = new StreamWriter(file);
627 int primCount = 0;
628 stream.WriteLine("<scene>\n");
629 foreach (EntityBase ent in Entities.Values)
630 {
631 if (ent is SceneObjectGroup)
632 {
633 stream.WriteLine(((SceneObjectGroup)ent).ToXmlString());
634 primCount++;
635 }
636 }
637 stream.WriteLine("</scene>\n");
638 stream.Close();
639 file.Close();
640 }
641
642
566 #endregion 643 #endregion
567 644
568 #region Add/Remove Avatar Methods 645 #region Add/Remove Avatar Methods
@@ -632,6 +709,7 @@ namespace OpenSim.Region.Environment.Scenes
632 client.OnFetchInventory += commsManager.UserProfiles.HandleFetchInventory; 709 client.OnFetchInventory += commsManager.UserProfiles.HandleFetchInventory;
633 client.OnAssetUploadRequest += commsManager.TransactionsManager.HandleUDPUploadRequest; 710 client.OnAssetUploadRequest += commsManager.TransactionsManager.HandleUDPUploadRequest;
634 client.OnXferReceive += commsManager.TransactionsManager.HandleXfer; 711 client.OnXferReceive += commsManager.TransactionsManager.HandleXfer;
712 // client.OnRequestXfer += RequestXfer;
635 713
636 client.OnGrabObject += ProcessObjectGrab; 714 client.OnGrabObject += ProcessObjectGrab;
637 } 715 }
@@ -950,7 +1028,7 @@ namespace OpenSim.Region.Environment.Scenes
950 AgentCircuitData agent = remoteClient.RequestClientInfo(); 1028 AgentCircuitData agent = remoteClient.RequestClientInfo();
951 agent.BaseFolder = LLUUID.Zero; 1029 agent.BaseFolder = LLUUID.Zero;
952 agent.InventoryFolder = LLUUID.Zero; 1030 agent.InventoryFolder = LLUUID.Zero;
953// agent.startpos = new LLVector3(128, 128, 70); 1031 // agent.startpos = new LLVector3(128, 128, 70);
954 agent.startpos = position; 1032 agent.startpos = position;
955 agent.child = true; 1033 agent.child = true;
956 commsManager.InterRegion.InformRegionOfChildAgent(regionHandle, agent); 1034 commsManager.InterRegion.InformRegionOfChildAgent(regionHandle, agent);
@@ -1121,7 +1199,15 @@ namespace OpenSim.Region.Environment.Scenes
1121 item.assetID = asset.FullID; 1199 item.assetID = asset.FullID;
1122 userInfo.UpdateItem(remoteClient.AgentId, item); 1200 userInfo.UpdateItem(remoteClient.AgentId, item);
1123 1201
1124 // remoteClient.SendInventoryItemUpdate(item); 1202 // remoteClient.SendInventoryItemUpdate(item);
1203 if (item.invType == 7)
1204 {
1205 //do we want to know about updated note cards?
1206 }
1207 else if (item.invType == 10)
1208 {
1209 // do we want to know about updated scripts
1210 }
1125 1211
1126 return (asset.FullID); 1212 return (asset.FullID);
1127 } 1213 }
diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs
index 421a981..1e6cd8f 100644
--- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs
@@ -212,7 +212,6 @@ namespace OpenSim.Region.Environment.Scenes
212 public string ToXmlString() 212 public string ToXmlString()
213 { 213 {
214 StringWriter sw = new StringWriter(); 214 StringWriter sw = new StringWriter();
215 //StreamWriter st = new StreamWriter("testxml.txt");
216 XmlTextWriter writer = new XmlTextWriter(sw); 215 XmlTextWriter writer = new XmlTextWriter(sw);
217 writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); 216 writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty);
218 writer.WriteStartElement(String.Empty, "RootPart", String.Empty); 217 writer.WriteStartElement(String.Empty, "RootPart", String.Empty);
@@ -231,11 +230,7 @@ namespace OpenSim.Region.Environment.Scenes
231 writer.WriteEndElement(); 230 writer.WriteEndElement();
232 writer.WriteEndElement(); 231 writer.WriteEndElement();
233 writer.Close(); 232 writer.Close();
234 // System.Console.WriteLine("prim: " + sw.ToString());
235 return sw.ToString(); 233 return sw.ToString();
236 // st.Close();
237 // return "";
238
239 } 234 }
240 235
241 #region Copying 236 #region Copying
@@ -557,12 +552,26 @@ namespace OpenSim.Region.Environment.Scenes
557 /// </summary> 552 /// </summary>
558 /// <param name="remoteClient"></param> 553 /// <param name="remoteClient"></param>
559 /// <param name="localID"></param> 554 /// <param name="localID"></param>
560 public void GetPartInventory(IClientAPI remoteClient, uint localID) 555 public void GetPartInventoryFileName(IClientAPI remoteClient, uint localID)
561 { 556 {
562 SceneObjectPart part = this.GetChildPrim(localID); 557 SceneObjectPart part = this.GetChildPrim(localID);
563 if (part != null) 558 if (part != null)
564 { 559 {
565 part.GetInventory(remoteClient, localID); 560 part.GetInventoryFileName(remoteClient, localID);
561 }
562 }
563
564 /// <summary>
565 ///
566 /// </summary>
567 /// <param name="remoteClient"></param>
568 /// <param name="partID"></param>
569 public void RequestInventoryFile(IClientAPI remoteClient, uint localID, ulong xferID)
570 {
571 SceneObjectPart part = this.GetChildPrim(localID);
572 if (part != null)
573 {
574 part.RequestInventoryFile(remoteClient, xferID);
566 } 575 }
567 } 576 }
568 577
@@ -636,6 +645,7 @@ namespace OpenSim.Region.Environment.Scenes
636 public void UpdateGroupPosition(LLVector3 pos) 645 public void UpdateGroupPosition(LLVector3 pos)
637 { 646 {
638 this.AbsolutePosition = pos; 647 this.AbsolutePosition = pos;
648
639 } 649 }
640 650
641 /// <summary> 651 /// <summary>
diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs
index 1cfe9c8..c8a7515 100644
--- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs
@@ -31,7 +31,7 @@ namespace OpenSim.Region.Environment.Scenes
31 public uint GroupMask = FULL_MASK_PERMISSIONS; 31 public uint GroupMask = FULL_MASK_PERMISSIONS;
32 public uint EveryoneMask = FULL_MASK_PERMISSIONS; 32 public uint EveryoneMask = FULL_MASK_PERMISSIONS;
33 public uint BaseMask = FULL_MASK_PERMISSIONS; 33 public uint BaseMask = FULL_MASK_PERMISSIONS;
34 34
35 protected byte[] m_particleSystem = new byte[0]; 35 protected byte[] m_particleSystem = new byte[0];
36 36
37 protected SceneObjectGroup m_parentGroup; 37 protected SceneObjectGroup m_parentGroup;
@@ -47,7 +47,7 @@ namespace OpenSim.Region.Environment.Scenes
47 public LLUUID UUID 47 public LLUUID UUID
48 { 48 {
49 get { return m_uuid; } 49 get { return m_uuid; }
50 set { m_uuid = value ; } 50 set { m_uuid = value; }
51 } 51 }
52 52
53 protected uint m_localID; 53 protected uint m_localID;
@@ -64,7 +64,7 @@ namespace OpenSim.Region.Environment.Scenes
64 set { m_name = value; } 64 set { m_name = value; }
65 } 65 }
66 66
67 protected LLObject.ObjectFlags m_flags = (LLObject.ObjectFlags)32 + 65536 + 131072 + 256 + 4 + 8 + 2048 + 524288 + 268435456 + 128; 67 protected LLObject.ObjectFlags m_flags = (LLObject.ObjectFlags)32 + 65536 + 131072 + 256 + 4 + 8 + 268435456 + 128;
68 public uint ObjectFlags 68 public uint ObjectFlags
69 { 69 {
70 get { return (uint)m_flags; } 70 get { return (uint)m_flags; }
@@ -221,7 +221,6 @@ namespace OpenSim.Region.Environment.Scenes
221 this.AngularVelocity = new LLVector3(0, 0, 0); 221 this.AngularVelocity = new LLVector3(0, 0, 0);
222 this.Acceleration = new LLVector3(0, 0, 0); 222 this.Acceleration = new LLVector3(0, 0, 0);
223 223
224
225 224
226 //temporary code just so the m_flags field doesn't give a compiler warning 225 //temporary code just so the m_flags field doesn't give a compiler warning
227 if (m_flags == LLObject.ObjectFlags.AllowInventoryDrop) 226 if (m_flags == LLObject.ObjectFlags.AllowInventoryDrop)
@@ -233,6 +232,7 @@ namespace OpenSim.Region.Environment.Scenes
233 232
234 /// <summary> 233 /// <summary>
235 /// Re/create a SceneObjectPart (prim) 234 /// Re/create a SceneObjectPart (prim)
235 /// currently not used, and maybe won't be
236 /// </summary> 236 /// </summary>
237 /// <param name="regionHandle"></param> 237 /// <param name="regionHandle"></param>
238 /// <param name="parent"></param> 238 /// <param name="parent"></param>
@@ -396,13 +396,59 @@ namespace OpenSim.Region.Environment.Scenes
396 #endregion 396 #endregion
397 397
398 #region Inventory 398 #region Inventory
399 public void GetInventory(IClientAPI client, uint localID) 399 /// <summary>
400 ///
401 /// </summary>
402 /// <param name="client"></param>
403 /// <param name="localID"></param>
404 public void GetInventoryFileName(IClientAPI client, uint localID)
400 { 405 {
401 if (localID == this.m_localID) 406 if (localID == this.m_localID)
402 { 407 {
408 // client.SendTaskInventory(this.m_uuid, 0, Helpers.StringToField("primInventory"));
403 client.SendTaskInventory(this.m_uuid, 0, new byte[0]); 409 client.SendTaskInventory(this.m_uuid, 0, new byte[0]);
404 } 410 }
405 } 411 }
412
413 /// <summary>
414 ///
415 /// </summary>
416 /// <param name="client"></param>
417 /// <param name="xferID"></param>
418 public void RequestInventoryFile(IClientAPI client, ulong xferID)
419 {
420 // a test item
421 InventoryStringBuilder invString = new InventoryStringBuilder();
422 invString.AddItemStart();
423 invString.AddNameValueLine("item_id", LLUUID.Random().ToStringHyphenated());
424 invString.AddNameValueLine("parent_id", this.UUID.ToStringHyphenated());
425
426 invString.AddPermissionsStart();
427 invString.AddNameValueLine("base_mask", "0x7FFFFFFF");
428 invString.AddNameValueLine("owner_mask", "0x7FFFFFFF");
429 invString.AddNameValueLine("group_mask", "0x7FFFFFFF");
430 invString.AddNameValueLine("everyone_mask", "0x7FFFFFFF");
431 invString.AddNameValueLine("next_owner_mask", "0x7FFFFFFF");
432 invString.AddNameValueLine("creator_id", client.AgentId.ToStringHyphenated());
433 invString.AddNameValueLine("owner_id", client.AgentId.ToStringHyphenated());
434 invString.AddNameValueLine("last_owner_id", LLUUID.Zero.ToStringHyphenated());
435 invString.AddNameValueLine("group_id", LLUUID.Zero.ToStringHyphenated());
436 invString.AddSectionEnd();
437
438 invString.AddNameValueLine("asset_id", "00000000-0000-0000-9999-000000000002");
439 invString.AddNameValueLine("type", "texture");
440 invString.AddNameValueLine("inv_type" , "texture");
441 invString.AddNameValueLine("flags", "0x00");
442 invString.AddNameValueLine("name", "Test inventory" + "|");
443 invString.AddNameValueLine("desc", "test description" + "|");
444 invString.AddNameValueLine("creation_date", "10000");
445 invString.AddSectionEnd();
446
447 byte[] fileInv = Helpers.StringToField(invString.BuildString);
448 byte[] data = new byte[fileInv.Length + 4];
449 Array.Copy(fileInv, 0,data , 4, fileInv.Length);
450 client.SendXferPacket(xferID, 0 + 0x80000000, data);
451 }
406 #endregion 452 #endregion
407 453
408 #region ExtraParams 454 #region ExtraParams
@@ -422,7 +468,7 @@ namespace OpenSim.Region.Environment.Scenes
422 Array.Copy(data, 0, this.m_shape.ExtraParams, i, data.Length); 468 Array.Copy(data, 0, this.m_shape.ExtraParams, i, data.Length);
423 469
424 this.ScheduleFullUpdate(); 470 this.ScheduleFullUpdate();
425 471
426 } 472 }
427 #endregion 473 #endregion
428 474
@@ -497,7 +543,7 @@ namespace OpenSim.Region.Environment.Scenes
497 /// <param name="remoteClient"></param> 543 /// <param name="remoteClient"></param>
498 public void SendFullUpdate(IClientAPI remoteClient) 544 public void SendFullUpdate(IClientAPI remoteClient)
499 { 545 {
500 m_parentGroup.SendPartFullUpdate( remoteClient, this ); 546 m_parentGroup.SendPartFullUpdate(remoteClient, this);
501 } 547 }
502 548
503 /// <summary> 549 /// <summary>
@@ -580,7 +626,46 @@ namespace OpenSim.Region.Environment.Scenes
580 626
581 public void SetText(string text, Vector3 color, double alpha) 627 public void SetText(string text, Vector3 color, double alpha)
582 { 628 {
583 Text = text; 629 Text = text;
630 }
631
632 public class InventoryStringBuilder
633 {
634 public string BuildString = "";
635
636 public InventoryStringBuilder()
637 {
638
639 }
640
641 public void AddItemStart()
642 {
643 BuildString += "\tinv_item\t0\n";
644 BuildString += "\t{\n";
645 }
646
647 public void AddPermissionsStart()
648 {
649 BuildString += "\tpermissions 0\n";
650 BuildString += "\t{\n";
651 }
652
653 public void AddSectionEnd()
654 {
655 BuildString += "\t}\n";
656 }
657
658 public void AddLine(string addLine)
659 {
660 BuildString += addLine;
661 }
662
663 public void AddNameValueLine(string name, string value)
664 {
665 BuildString += "\t\t";
666 BuildString += name + "\t";
667 BuildString += value + "\n";
668 }
584 } 669 }
585 } 670 }
586} 671}
diff --git a/OpenSim/Region/Environment/Scenes/ScenePresence.cs b/OpenSim/Region/Environment/Scenes/ScenePresence.cs
index 7dcb760..0393a2a 100644
--- a/OpenSim/Region/Environment/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Environment/Scenes/ScenePresence.cs
@@ -59,7 +59,7 @@ namespace OpenSim.Region.Environment.Scenes
59 59
60 private ulong m_regionHandle; 60 private ulong m_regionHandle;
61 61
62 public bool childAgent = false; 62 public bool childAgent = true;
63 public bool IsRestrictedToRegion = false; 63 public bool IsRestrictedToRegion = false;
64 64
65 private bool newForce = false; 65 private bool newForce = false;
@@ -495,6 +495,7 @@ namespace OpenSim.Region.Environment.Scenes
495 this.SendArrearanceToAllOtherAgents(); 495 this.SendArrearanceToAllOtherAgents();
496 496
497 this.m_scene.SendAllSceneObjectsToClient(this.ControllingClient); 497 this.m_scene.SendAllSceneObjectsToClient(this.ControllingClient);
498 this.ControllingClient.SendViewerTime(this.m_scene.TimePhase);
498 } 499 }
499 500
500 /// <summary> 501 /// <summary>