aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment')
-rw-r--r--OpenSim/Region/Environment/Modules/World/Land/LandObject.cs70
-rw-r--r--OpenSim/Region/Environment/Scenes/Scene.Inventory.cs352
2 files changed, 312 insertions, 110 deletions
diff --git a/OpenSim/Region/Environment/Modules/World/Land/LandObject.cs b/OpenSim/Region/Environment/Modules/World/Land/LandObject.cs
index 54870d8..98f3a3a 100644
--- a/OpenSim/Region/Environment/Modules/World/Land/LandObject.cs
+++ b/OpenSim/Region/Environment/Modules/World/Land/LandObject.cs
@@ -596,23 +596,32 @@ namespace OpenSim.Region.Environment.Modules.World.Land
596 if (m_scene.ExternalChecks.ExternalChecksCanEditParcel(remote_client.AgentId, this)) 596 if (m_scene.ExternalChecks.ExternalChecksCanEditParcel(remote_client.AgentId, this))
597 { 597 {
598 List<uint> resultLocalIDs = new List<uint>(); 598 List<uint> resultLocalIDs = new List<uint>();
599 foreach (SceneObjectGroup obj in primsOverMe) 599 try
600 { 600 {
601 if (obj.LocalId > 0) 601 lock (primsOverMe)
602 { 602 {
603 if (request_type == LandChannel.LAND_SELECT_OBJECTS_OWNER && obj.OwnerID == landData.ownerID) 603 foreach (SceneObjectGroup obj in primsOverMe)
604 {
605 resultLocalIDs.Add(obj.LocalId);
606 }
607 // else if (request_type == LandManager.LAND_SELECT_OBJECTS_GROUP && ...) // TODO: group support
608 // {
609 // }
610 else if (request_type == LandChannel.LAND_SELECT_OBJECTS_OTHER &&
611 obj.OwnerID != remote_client.AgentId)
612 { 604 {
613 resultLocalIDs.Add(obj.LocalId); 605 if (obj.LocalId > 0)
606 {
607 if (request_type == LandChannel.LAND_SELECT_OBJECTS_OWNER && obj.OwnerID == landData.ownerID)
608 {
609 resultLocalIDs.Add(obj.LocalId);
610 }
611 // else if (request_type == LandManager.LAND_SELECT_OBJECTS_GROUP && ...) // TODO: group support
612 // {
613 // }
614 else if (request_type == LandChannel.LAND_SELECT_OBJECTS_OTHER &&
615 obj.OwnerID != remote_client.AgentId)
616 {
617 resultLocalIDs.Add(obj.LocalId);
618 }
619 }
614 } 620 }
615 } 621 }
622 } catch (InvalidOperationException)
623 {
624 m_log.Error("[LAND]: Unable to force select the parcel objects. Arr.");
616 } 625 }
617 626
618 remote_client.sendForceClientSelectObjects(resultLocalIDs); 627 remote_client.sendForceClientSelectObjects(resultLocalIDs);
@@ -633,26 +642,37 @@ namespace OpenSim.Region.Environment.Modules.World.Land
633 { 642 {
634 Dictionary<LLUUID, int> primCount = new Dictionary<LLUUID, int>(); 643 Dictionary<LLUUID, int> primCount = new Dictionary<LLUUID, int>();
635 644
636 foreach (SceneObjectGroup obj in primsOverMe) 645 lock (primsOverMe)
637 { 646 {
638 try 647 try
639 { 648 {
640 if (!primCount.ContainsKey(obj.OwnerID)) 649
650 foreach (SceneObjectGroup obj in primsOverMe)
641 { 651 {
642 primCount.Add(obj.OwnerID, 0); 652 try
653 {
654 if (!primCount.ContainsKey(obj.OwnerID))
655 {
656 primCount.Add(obj.OwnerID, 0);
657 }
658 }
659 catch (NullReferenceException)
660 {
661 m_log.Info("[LAND]: " + "Got Null Reference when searching land owners from the parcel panel");
662 }
663 try
664 {
665 primCount[obj.OwnerID] += obj.PrimCount;
666 }
667 catch (KeyNotFoundException)
668 {
669 m_log.Error("[LAND]: Unable to match a prim with it's owner.");
670 }
643 } 671 }
644 } 672 }
645 catch (NullReferenceException) 673 catch (InvalidOperationException)
646 {
647 m_log.Info("[LAND]: " + "Got Null Reference when searching land owners from the parcel panel");
648 }
649 try
650 {
651 primCount[obj.OwnerID] += obj.PrimCount;
652 }
653 catch (KeyNotFoundException)
654 { 674 {
655 m_log.Error("[LAND]: Unable to match a prim with it's owner."); 675 m_log.Error("[LAND]: Unable to Enumerate Land object arr.");
656 } 676 }
657 } 677 }
658 678
diff --git a/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs b/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs
index e92178c..a284ba5 100644
--- a/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs
@@ -70,6 +70,24 @@ namespace OpenSim.Region.Environment.Scenes
70 AddInventoryItem(agentID, item); 70 AddInventoryItem(agentID, item);
71 } 71 }
72 72
73 public bool AddInventoryItemReturned(LLUUID AgentId, InventoryItemBase item)
74 {
75 CachedUserInfo userInfo
76 = CommsManager.UserProfileCacheService.GetUserDetails(AgentId);
77 if (userInfo != null)
78 {
79 userInfo.AddItem(item);
80 return true;
81 }
82 else
83 {
84 m_log.ErrorFormat(
85 "[AGENT INVENTORY]: Agent was not found for add of item {1} {2}", item.Name, item.ID);
86
87 return false;
88 }
89 }
90
73 /// <summary> 91 /// <summary>
74 /// Add an inventory item to an avatar's inventory. 92 /// Add an inventory item to an avatar's inventory.
75 /// </summary> 93 /// </summary>
@@ -1060,6 +1078,7 @@ namespace OpenSim.Region.Environment.Scenes
1060 } 1078 }
1061 } 1079 }
1062 1080
1081
1063 /// <summary> 1082 /// <summary>
1064 /// Called when an object is removed from the environment into inventory. 1083 /// Called when an object is removed from the environment into inventory.
1065 /// </summary> 1084 /// </summary>
@@ -1068,123 +1087,178 @@ namespace OpenSim.Region.Environment.Scenes
1068 public virtual void DeRezObject(Packet packet, IClientAPI remoteClient) 1087 public virtual void DeRezObject(Packet packet, IClientAPI remoteClient)
1069 { 1088 {
1070 DeRezObjectPacket DeRezPacket = (DeRezObjectPacket) packet; 1089 DeRezObjectPacket DeRezPacket = (DeRezObjectPacket) packet;
1090
1091 LLUUID folderID = LLUUID.Zero;
1071 1092
1072 if (DeRezPacket.AgentBlock.DestinationID == LLUUID.Zero) 1093
1073 { 1094
1074 //currently following code not used (or don't know of any case of destination being zero 1095
1075 } 1096
1076 else 1097 foreach (DeRezObjectPacket.ObjectDataBlock Data in DeRezPacket.ObjectData)
1077 { 1098 {
1078 foreach (DeRezObjectPacket.ObjectDataBlock Data in DeRezPacket.ObjectData)
1079 {
1080// m_log.DebugFormat( 1099// m_log.DebugFormat(
1081// "[AGENT INVENTORY]: Received request to derez {0} into folder {1}", 1100// "[AGENT INVENTORY]: Received request to derez {0} into folder {1}",
1082// Data.ObjectLocalID, DeRezPacket.AgentBlock.DestinationID); 1101// Data.ObjectLocalID, DeRezPacket.AgentBlock.DestinationID);
1083 1102
1084 EntityBase selectedEnt = null; 1103 EntityBase selectedEnt = null;
1085 //m_log.Info("[CLIENT]: LocalID:" + Data.ObjectLocalID.ToString()); 1104 //m_log.Info("[CLIENT]: LocalID:" + Data.ObjectLocalID.ToString());
1086 1105
1087 List<EntityBase> EntityList = GetEntities(); 1106 List<EntityBase> EntityList = GetEntities();
1088 1107
1089 foreach (EntityBase ent in EntityList) 1108 foreach (EntityBase ent in EntityList)
1109 {
1110 if (ent.LocalId == Data.ObjectLocalID)
1090 { 1111 {
1091 if (ent.LocalId == Data.ObjectLocalID) 1112 selectedEnt = ent;
1092 { 1113 break;
1093 selectedEnt = ent;
1094 break;
1095 }
1096 } 1114 }
1097 if (selectedEnt != null) 1115 }
1116 if (selectedEnt != null)
1117 {
1118 bool permissionToTake = false;
1119 bool permissionToDelete = false;
1120 if (DeRezPacket.AgentBlock.Destination == 1)// Take Copy
1098 { 1121 {
1099 bool permissionToTake = false; 1122 permissionToTake = ExternalChecks.ExternalChecksCanTakeCopyObject(((SceneObjectGroup)selectedEnt).UUID, remoteClient.AgentId);
1100 bool permissionToDelete = false; 1123 permissionToDelete = false; //Just taking copy!
1101 if (DeRezPacket.AgentBlock.Destination == 1)// Take Copy
1102 {
1103 permissionToTake = ExternalChecks.ExternalChecksCanTakeCopyObject(((SceneObjectGroup)selectedEnt).UUID, remoteClient.AgentId);
1104 permissionToDelete = false; //Just taking copy!
1105 1124
1106 } 1125 }
1107 else if (DeRezPacket.AgentBlock.Destination == 4) //Take 1126 else if (DeRezPacket.AgentBlock.Destination == 4) //Take
1108 { 1127 {
1109 // Take 1128 // Take
1110 permissionToTake = ExternalChecks.ExternalChecksCanTakeObject(((SceneObjectGroup)selectedEnt).UUID, remoteClient.AgentId); 1129 permissionToTake = ExternalChecks.ExternalChecksCanTakeObject(((SceneObjectGroup)selectedEnt).UUID, remoteClient.AgentId);
1111 permissionToDelete = permissionToTake; //If they can take, they can delete! 1130 permissionToDelete = permissionToTake; //If they can take, they can delete!
1112 } 1131 }
1113 1132
1114 else if (DeRezPacket.AgentBlock.Destination == 6) //Delete 1133 else if (DeRezPacket.AgentBlock.Destination == 6) //Delete
1115 { 1134 {
1116 permissionToTake = false; 1135 permissionToTake = ExternalChecks.ExternalChecksCanDeleteObject(((SceneObjectGroup)selectedEnt).UUID, remoteClient.AgentId);
1117 permissionToDelete = ExternalChecks.ExternalChecksCanDeleteObject(((SceneObjectGroup)selectedEnt).UUID, remoteClient.AgentId); 1136 permissionToDelete = ExternalChecks.ExternalChecksCanDeleteObject(((SceneObjectGroup)selectedEnt).UUID, remoteClient.AgentId);
1118 } 1137 }
1138 else if (DeRezPacket.AgentBlock.Destination == 9) //Return
1139 {
1140 permissionToTake = ExternalChecks.ExternalChecksCanDeleteObject(((SceneObjectGroup)selectedEnt).UUID, remoteClient.AgentId);
1141 permissionToDelete = ExternalChecks.ExternalChecksCanDeleteObject(((SceneObjectGroup)selectedEnt).UUID, remoteClient.AgentId);
1142 }
1119 1143
1120 SceneObjectGroup objectGroup = (SceneObjectGroup)selectedEnt; 1144 SceneObjectGroup objectGroup = (SceneObjectGroup)selectedEnt;
1145
1146 if (permissionToTake)
1147 {
1121 1148
1122 if (permissionToTake) 1149 string sceneObjectXml = objectGroup.ToXmlString();
1150
1151 CachedUserInfo userInfo =
1152 CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
1153 if (userInfo != null)
1123 { 1154 {
1124 string sceneObjectXml = objectGroup.ToXmlString(); 1155 string searchFolder = "";
1156
1157 if (DeRezPacket.AgentBlock.Destination == 6)
1158 searchFolder = "Trash";
1159 else if (DeRezPacket.AgentBlock.Destination == 9)
1160 searchFolder = "Lost And Found";
1161
1162 // If we're deleting someone else's item, it goes back to their deleted items folder
1163 // If we're returning someone's item, it goes back to the owner's Lost And Found folder.
1125 1164
1126 CachedUserInfo userInfo = 1165 if (DeRezPacket.AgentBlock.DestinationID == LLUUID.Zero || (DeRezPacket.AgentBlock.Destination == 6 && objectGroup.OwnerID != remoteClient.AgentId))
1127 CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
1128 if (userInfo != null)
1129 { 1166 {
1130 AssetBase asset = CreateAsset( 1167 List<InventoryFolderBase> subrootfolders = userInfo.RootFolder.RequestListOfFolders();
1131 ((SceneObjectGroup) selectedEnt).GetPartName(selectedEnt.LocalId), 1168 foreach (InventoryFolderBase flder in subrootfolders)
1132 ((SceneObjectGroup) selectedEnt).GetPartDescription(selectedEnt.LocalId),
1133 (sbyte) InventoryType.Object,
1134 (sbyte) AssetType.Object,
1135 Helpers.StringToField(sceneObjectXml));
1136 AssetCache.AddAsset(asset);
1137
1138 InventoryItemBase item = new InventoryItemBase();
1139 item.Creator = objectGroup.RootPart.CreatorID;
1140 item.Owner = remoteClient.AgentId;
1141 item.ID = LLUUID.Random();
1142 item.AssetID = asset.FullID;
1143 item.Description = asset.Description;
1144 item.Name = asset.Name;
1145 item.AssetType = asset.Type;
1146 item.InvType = asset.InvType;
1147 item.Folder = DeRezPacket.AgentBlock.DestinationID;
1148 if ((remoteClient.AgentId != objectGroup.RootPart.OwnerID) && ExternalChecks.ExternalChecksPropagatePermissions())
1149 { 1169 {
1150 uint perms=objectGroup.GetEffectivePermissions(); 1170 if (flder.Name == "Lost And Found")
1151 uint nextPerms=(perms & 7) << 13; 1171 {
1152 if ((nextPerms & (uint)PermissionMask.Copy) == 0) 1172 folderID = flder.ID;
1153 perms &= ~(uint)PermissionMask.Copy; 1173 break;
1154 if ((nextPerms & (uint)PermissionMask.Transfer) == 0) 1174 }
1155 perms &= ~(uint)PermissionMask.Transfer;
1156 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
1157 perms &= ~(uint)PermissionMask.Modify;
1158
1159 item.BasePermissions = perms & objectGroup.RootPart.NextOwnerMask;
1160 item.CurrentPermissions = item.BasePermissions;
1161 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
1162 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask & objectGroup.RootPart.NextOwnerMask;
1163 item.CurrentPermissions |= 8; // Slam!
1164 } 1175 }
1165 else 1176
1177 if (folderID == LLUUID.Zero)
1166 { 1178 {
1167 item.BasePermissions = objectGroup.GetEffectivePermissions(); 1179 folderID = userInfo.RootFolder.ID;
1168 item.CurrentPermissions = objectGroup.GetEffectivePermissions();
1169 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
1170 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask;
1171 } 1180 }
1181 //currently following code not used (or don't know of any case of destination being zero
1182 }
1183 else
1184 {
1185 folderID = DeRezPacket.AgentBlock.DestinationID;
1186 }
1187
1188 AssetBase asset = CreateAsset(
1189 ((SceneObjectGroup) selectedEnt).GetPartName(selectedEnt.LocalId),
1190 ((SceneObjectGroup) selectedEnt).GetPartDescription(selectedEnt.LocalId),
1191 (sbyte) InventoryType.Object,
1192 (sbyte) AssetType.Object,
1193 Helpers.StringToField(sceneObjectXml));
1194 AssetCache.AddAsset(asset);
1172 1195
1173 // TODO: add the new fields (Flags, Sale info, etc) 1196 InventoryItemBase item = new InventoryItemBase();
1197 item.Creator = objectGroup.RootPart.CreatorID;
1174 1198
1175 userInfo.AddItem(item); 1199 if (DeRezPacket.AgentBlock.Destination == 1 || DeRezPacket.AgentBlock.Destination == 4)// Take / Copy
1200 item.Owner = remoteClient.AgentId;
1201 else // Delete / Return
1202 item.Owner = objectGroup.OwnerID;
1203
1204 item.ID = LLUUID.Random();
1205 item.AssetID = asset.FullID;
1206 item.Description = asset.Description;
1207 item.Name = asset.Name;
1208 item.AssetType = asset.Type;
1209 item.InvType = asset.InvType;
1210 item.Folder = folderID;
1211 if ((remoteClient.AgentId != objectGroup.RootPart.OwnerID) && ExternalChecks.ExternalChecksPropagatePermissions())
1212 {
1213 uint perms=objectGroup.GetEffectivePermissions();
1214 uint nextPerms=(perms & 7) << 13;
1215 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
1216 perms &= ~(uint)PermissionMask.Copy;
1217 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
1218 perms &= ~(uint)PermissionMask.Transfer;
1219 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
1220 perms &= ~(uint)PermissionMask.Modify;
1221
1222 item.BasePermissions = perms & objectGroup.RootPart.NextOwnerMask;
1223 item.CurrentPermissions = item.BasePermissions;
1224 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
1225 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask & objectGroup.RootPart.NextOwnerMask;
1226 item.CurrentPermissions |= 8; // Slam!
1227 }
1228 else
1229 {
1230 item.BasePermissions = objectGroup.GetEffectivePermissions();
1231 item.CurrentPermissions = objectGroup.GetEffectivePermissions();
1232 item.NextPermissions = objectGroup.RootPart.NextOwnerMask;
1233 item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask;
1234 }
1235
1236 // TODO: add the new fields (Flags, Sale info, etc)
1237
1238 userInfo.AddItem(item);
1239 if (item.Owner == remoteClient.AgentId)
1240 {
1176 remoteClient.SendInventoryItemCreateUpdate(item); 1241 remoteClient.SendInventoryItemCreateUpdate(item);
1177 } 1242 }
1243 else
1244 {
1245 ScenePresence notifyUser = GetScenePresence(item.Owner);
1246 if (notifyUser != null)
1247 {
1248 notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item);
1249 }
1250 }
1178 } 1251 }
1252 }
1179 1253
1180 1254
1181 if (permissionToDelete) 1255 if (permissionToDelete)
1182 { 1256 {
1183 DeleteSceneObjectGroup(objectGroup); 1257 DeleteSceneObjectGroup(objectGroup);
1184 }
1185 } 1258 }
1186 } 1259 }
1187 } 1260 }
1261
1188 } 1262 }
1189 1263
1190 public void updateKnownAsset(IClientAPI remoteClient, SceneObjectGroup grp, LLUUID assetID, LLUUID agentID) 1264 public void updateKnownAsset(IClientAPI remoteClient, SceneObjectGroup grp, LLUUID assetID, LLUUID agentID)
@@ -1599,6 +1673,114 @@ namespace OpenSim.Region.Environment.Scenes
1599 } 1673 }
1600 return null; 1674 return null;
1601 } 1675 }
1676 public virtual bool returnObjects(SceneObjectGroup[] returnobjects, LLUUID AgentId)
1677 {
1678 if (returnobjects.Length <= 0)
1679 return false;
1680
1681 // for the moment we're going to store them individually.. however, in the future, the rezObject
1682 // will be able to have more items.
1683
1684 //string returnstring = "";
1685 //returnstring += "<scene>\n";
1686 //for (int i = 0; i < returnobjects.Length; i++)
1687 //{
1688 // returnstring += grp.ToXmlString2();
1689 //}
1690 //returnstring += "</scene>\n";
1691
1692
1693 CachedUserInfo userInfo =
1694 CommsManager.UserProfileCacheService.GetUserDetails(AgentId);
1695 if (userInfo != null)
1696 {
1697 LLUUID folderID = LLUUID.Zero;
1698
1699 List<InventoryFolderBase> subrootfolders = userInfo.RootFolder.RequestListOfFolders();
1700 foreach (InventoryFolderBase flder in subrootfolders)
1701 {
1702 if (flder.Name == "Lost And Found")
1703 {
1704 folderID = flder.ID;
1705 break;
1706 }
1707 }
1708
1709 if (folderID == LLUUID.Zero)
1710 {
1711 folderID = userInfo.RootFolder.ID;
1712 }
1713
1714 bool permissionToDelete = false;
1715
1716 for (int i = 0; i < returnobjects.Length; i++)
1717 {
1718 permissionToDelete = ExternalChecks.ExternalChecksCanDeleteObject(returnobjects[i].UUID, AgentId);
1719
1720 // If the user doesn't have permission, go on to the next one.
1721 if (!permissionToDelete)
1722 continue;
1723
1724 string sceneObjectXml = returnobjects[i].ToXmlString2();
1725 AssetBase asset = CreateAsset(
1726 returnobjects[i].GetPartName(returnobjects[i].LocalId),
1727 returnobjects[i].GetPartDescription(returnobjects[i].LocalId),
1728 (sbyte)InventoryType.Object,
1729 (sbyte)AssetType.Object,
1730 Helpers.StringToField(sceneObjectXml));
1731 AssetCache.AddAsset(asset);
1732
1733 InventoryItemBase item = new InventoryItemBase();
1734 item.Creator = returnobjects[i].RootPart.CreatorID;
1735 item.Owner = AgentId;
1736 item.ID = LLUUID.Random();
1737 item.AssetID = asset.FullID;
1738 item.Description = asset.Description;
1739 item.Name = asset.Name;
1740 item.AssetType = asset.Type;
1741 item.InvType = asset.InvType;
1742 item.Folder = folderID;
1743 if ((AgentId != returnobjects[i].RootPart.OwnerID) && ExternalChecks.ExternalChecksPropagatePermissions())
1744 {
1745 uint perms = returnobjects[i].GetEffectivePermissions();
1746 uint nextPerms = (perms & 7) << 13;
1747 if ((nextPerms & (uint)PermissionMask.Copy) == 0)
1748 perms &= ~(uint)PermissionMask.Copy;
1749 if ((nextPerms & (uint)PermissionMask.Transfer) == 0)
1750 perms &= ~(uint)PermissionMask.Transfer;
1751 if ((nextPerms & (uint)PermissionMask.Modify) == 0)
1752 perms &= ~(uint)PermissionMask.Modify;
1753
1754 item.BasePermissions = perms & returnobjects[i].RootPart.NextOwnerMask;
1755 item.CurrentPermissions = item.BasePermissions;
1756 item.NextPermissions = returnobjects[i].RootPart.NextOwnerMask;
1757 item.EveryOnePermissions = returnobjects[i].RootPart.EveryoneMask & returnobjects[i].RootPart.NextOwnerMask;
1758 item.CurrentPermissions |= 8; // Slam!
1759 }
1760 else
1761 {
1762 item.BasePermissions = returnobjects[i].GetEffectivePermissions();
1763 item.CurrentPermissions = returnobjects[i].GetEffectivePermissions();
1764 item.NextPermissions = returnobjects[i].RootPart.NextOwnerMask;
1765 item.EveryOnePermissions = returnobjects[i].RootPart.EveryoneMask;
1766 }
1767
1768 // TODO: add the new fields (Flags, Sale info, etc)
1769
1770 userInfo.AddItem(item);
1771
1772 SceneObjectGroup ObjectDeleting = returnobjects[i];
1773
1774 returnobjects[i] = null;
1775
1776 DeleteSceneObjectGroup(ObjectDeleting);
1777 ObjectDeleting = null;
1778 }
1779 return true;
1780 }
1781 return false;
1782
1783 }
1602 1784
1603 } 1785 }
1604} 1786}