aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs8
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs149
-rw-r--r--OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs152
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs49
4 files changed, 208 insertions, 150 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index 86e10d4..fa9cd55 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -561,12 +561,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
561 // Finally, kill the agent we just created at the destination. 561 // Finally, kill the agent we just created at the destination.
562 m_aScene.SimulationService.CloseAgent(finalDestination, sp.UUID); 562 m_aScene.SimulationService.CloseAgent(finalDestination, sp.UUID);
563 563
564 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
564 } 565 }
565 566
566 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) 567 protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout)
567 { 568 {
568 logout = false; 569 logout = false;
569 return m_aScene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason); 570 bool success = m_aScene.SimulationService.CreateAgent(finalDestination, agentCircuit, teleportFlags, out reason);
571
572 if (success)
573 sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
574
575 return success;
570 } 576 }
571 577
572 protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent) 578 protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent)
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
index 0f422ae..7f9175d 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs
@@ -51,8 +51,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
51 51
52 private bool m_Initialized = false; 52 private bool m_Initialized = false;
53 53
54 private bool m_RestrictInventoryAccessAbroad = false;
55
56 private GatekeeperServiceConnector m_GatekeeperConnector; 54 private GatekeeperServiceConnector m_GatekeeperConnector;
57 55
58 #region ISharedRegionModule 56 #region ISharedRegionModule
@@ -71,10 +69,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
71 if (name == Name) 69 if (name == Name)
72 { 70 {
73 InitialiseCommon(source); 71 InitialiseCommon(source);
74 IConfig transferConfig = source.Configs["HGEntityTransferModule"];
75 if (transferConfig != null)
76 m_RestrictInventoryAccessAbroad = transferConfig.GetBoolean("RestrictInventoryAccessAbroad", false);
77
78 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name); 72 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: {0} enabled.", Name);
79 } 73 }
80 } 74 }
@@ -94,44 +88,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
94 client.OnTeleportHomeRequest += TeleportHome; 88 client.OnTeleportHomeRequest += TeleportHome;
95 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 89 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
96 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed); 90 client.OnConnectionClosed += new Action<IClientAPI>(OnConnectionClosed);
97 client.OnCompleteMovementToRegion += new Action<IClientAPI, bool>(OnCompleteMovementToRegion);
98 } 91 }
99 92
100 protected void OnCompleteMovementToRegion(IClientAPI client, bool arg2)
101 {
102 // HACK HACK -- just seeing how the viewer responds
103 // Let's send the Suitcase or the real root folder folder for incoming HG agents
104 // Visiting agents get their suitcase contents; incoming local users get their real root folder's content
105 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: OnCompleteMovementToRegion of user {0}", client.AgentId);
106 object sp = null;
107 if (client.Scene.TryGetScenePresence(client.AgentId, out sp))
108 {
109 if (sp is ScenePresence)
110 {
111 AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId);
112 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
113 {
114 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: ViaHGLogin");
115 if (m_RestrictInventoryAccessAbroad)
116 {
117 IUserManagement uMan = m_Scenes[0].RequestModuleInterface<IUserManagement>();
118 if (uMan.IsLocalGridUser(client.AgentId))
119 {
120 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local");
121 RestoreRootFolderContents(client);
122 }
123 else
124 {
125 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is foreign");
126 RestoreSuitcaseFolderContents(client);
127 }
128 }
129 }
130 }
131 }
132 }
133
134
135 public override void RegionLoaded(Scene scene) 93 public override void RegionLoaded(Scene scene)
136 { 94 {
137 base.RegionLoaded(scene); 95 base.RegionLoaded(scene);
@@ -141,12 +99,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
141 m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService); 99 m_GatekeeperConnector = new GatekeeperServiceConnector(scene.AssetService);
142 m_Initialized = true; 100 m_Initialized = true;
143 101
144 scene.AddCommand(
145 "HG", this, "send inventory",
146 "send inventory",
147 "Don't use this",
148 HandleSendInventory);
149
150 } 102 }
151 103
152 } 104 }
@@ -219,21 +171,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
219 bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, out reason); 171 bool success = connector.LoginAgentToGrid(agentCircuit, reg, finalDestination, out reason);
220 logout = success; // flag for later logout from this grid; this is an HG TP 172 logout = success; // flag for later logout from this grid; this is an HG TP
221 173
222 if (success && m_RestrictInventoryAccessAbroad) 174 if (success)
223 { 175 sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout);
224 IUserManagement uMan = m_aScene.RequestModuleInterface<IUserManagement>();
225 if (uMan != null && uMan.IsLocalGridUser(sp.UUID))
226 {
227 // local grid user
228 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is local");
229 RemoveRootFolderContents(sp.ControllingClient);
230 }
231 else
232 {
233 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: User is foreign");
234 RemoveSuitcaseFolderContents(sp.ControllingClient);
235 }
236 }
237 176
238 return success; 177 return success;
239 } 178 }
@@ -244,7 +183,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
244 } 183 }
245 } 184 }
246 185
247 return m_aScene.SimulationService.CreateAgent(reg, agentCircuit, teleportFlags, out reason); 186 return base.CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout);
248 } 187 }
249 188
250 public override void TeleportHome(UUID id, IClientAPI client) 189 public override void TeleportHome(UUID id, IClientAPI client)
@@ -348,15 +287,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
348 287
349 } 288 }
350 289
351 protected override void Fail(ScenePresence sp, GridRegion finalDestination, bool logout)
352 {
353 base.Fail(sp, finalDestination, logout);
354 if (logout && m_RestrictInventoryAccessAbroad)
355 {
356 RestoreRootFolderContents(sp.ControllingClient);
357 }
358 }
359
360 #endregion 290 #endregion
361 291
362 #region IUserAgentVerificationModule 292 #region IUserAgentVerificationModule
@@ -411,71 +341,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
411 341
412 #endregion 342 #endregion
413 343
414 private void RemoveRootFolderContents(IClientAPI client)
415 {
416 // TODO tell the viewer to remove the root folder's content
417 if (client is IClientCore)
418 {
419 IClientCore core = (IClientCore)client;
420 IClientInventory inv;
421
422 if (core.TryGet<IClientInventory>(out inv))
423 {
424 InventoryFolderBase root = m_Scenes[0].InventoryService.GetRootFolder(client.AgentId);
425 if (root != null)
426 {
427 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Removing root inventory for user {0}", client.Name);
428 InventoryCollection content = m_Scenes[0].InventoryService.GetFolderContent(client.AgentId, root.ID);
429 List<UUID> fids = new List<UUID>();
430 List<UUID> iids = new List<UUID>();
431 List<InventoryFolderBase> keep = new List<InventoryFolderBase>();
432
433 foreach (InventoryFolderBase f in content.Folders)
434 {
435 if (f.Name != "My Suitcase")
436 {
437 f.Name = f.Name + " (Unavailable)";
438 keep.Add(f);
439 }
440 }
441
442 // items directly under the root folder
443 foreach (InventoryItemBase it in content.Items)
444 it.Name = it.Name + " (Unavailable)"; ;
445
446 // Send the new names
447 inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray());
448
449 }
450 }
451 }
452 }
453
454 private void RemoveSuitcaseFolderContents(IClientAPI client)
455 {
456 }
457
458 private void RestoreRootFolderContents(IClientAPI client)
459 {
460 m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Restoring root folder");
461 if (client is IClientCore)
462 {
463 IClientCore core = (IClientCore)client;
464 IClientInventory inv;
465
466 if (core.TryGet<IClientInventory>(out inv))
467 {
468 InventoryFolderBase root = m_Scenes[0].InventoryService.GetRootFolder(client.AgentId);
469 InventoryCollection content = m_Scenes[0].InventoryService.GetFolderContent(client.AgentId, root.ID);
470
471 inv.SendBulkUpdateInventory(content.Folders.ToArray(), content.Items.ToArray());
472 }
473 }
474 }
475
476 private void RestoreSuitcaseFolderContents(IClientAPI client)
477 {
478 }
479 344
480 private GridRegion MakeRegion(AgentCircuitData aCircuit) 345 private GridRegion MakeRegion(AgentCircuitData aCircuit)
481 { 346 {
@@ -494,13 +359,5 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
494 return region; 359 return region;
495 } 360 }
496 361
497 protected void HandleSendInventory(string module, string[] cmd)
498 {
499 m_Scenes[0].ForEachClient(delegate(IClientAPI client)
500 {
501 RestoreRootFolderContents(client);
502 });
503 }
504
505 } 362 }
506} 363}
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
index d2fe388..a71584a 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs
@@ -30,6 +30,7 @@ using System.Collections.Generic;
30using System.Reflection; 30using System.Reflection;
31 31
32using OpenSim.Framework; 32using OpenSim.Framework;
33using OpenSim.Framework.Client;
33using OpenSim.Region.Framework.Interfaces; 34using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
35using OpenSim.Services.Connectors.Hypergrid; 36using OpenSim.Services.Connectors.Hypergrid;
@@ -57,6 +58,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
57 private string m_HomeURI; 58 private string m_HomeURI;
58 private bool m_OutboundPermission; 59 private bool m_OutboundPermission;
59 private string m_ThisGatekeeper; 60 private string m_ThisGatekeeper;
61 private bool m_RestrictInventoryAccessAbroad;
60 62
61// private bool m_Initialized = false; 63// private bool m_Initialized = false;
62 64
@@ -90,6 +92,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
90 m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI); 92 m_HomeURI = thisModuleConfig.GetString("HomeURI", m_HomeURI);
91 m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true); 93 m_OutboundPermission = thisModuleConfig.GetBoolean("OutboundPermission", true);
92 m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty); 94 m_ThisGatekeeper = thisModuleConfig.GetString("Gatekeeper", string.Empty);
95 m_RestrictInventoryAccessAbroad = thisModuleConfig.GetBoolean("RestrictInventoryAccessAbroad", false);
93 } 96 }
94 else 97 else
95 m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!"); 98 m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!");
@@ -105,13 +108,79 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
105 base.AddRegion(scene); 108 base.AddRegion(scene);
106 m_assMapper = new HGAssetMapper(scene, m_HomeURI); 109 m_assMapper = new HGAssetMapper(scene, m_HomeURI);
107 scene.EventManager.OnNewInventoryItemUploadComplete += UploadInventoryItem; 110 scene.EventManager.OnNewInventoryItemUploadComplete += UploadInventoryItem;
108 111 scene.EventManager.OnTeleportStart += TeleportStart;
112 scene.EventManager.OnTeleportFail += TeleportFail;
109 } 113 }
110 114
111 #endregion 115 #endregion
112 116
113 #region Event handlers 117 #region Event handlers
114 118
119 protected override void OnNewClient(IClientAPI client)
120 {
121 base.OnNewClient(client);
122 client.OnCompleteMovementToRegion += new Action<IClientAPI, bool>(OnCompleteMovementToRegion);
123 }
124
125 protected void OnCompleteMovementToRegion(IClientAPI client, bool arg2)
126 {
127 //m_log.DebugFormat("[HG INVENTORY ACCESS MODULE]: OnCompleteMovementToRegion of user {0}", client.Name);
128 object sp = null;
129 if (client.Scene.TryGetScenePresence(client.AgentId, out sp))
130 {
131 if (sp is ScenePresence)
132 {
133 AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId);
134 if ((aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0)
135 {
136 if (m_RestrictInventoryAccessAbroad)
137 {
138 IUserManagement uMan = m_Scene.RequestModuleInterface<IUserManagement>();
139 if (uMan.IsLocalGridUser(client.AgentId))
140 ProcessInventoryForComingHome(client);
141 else
142 ProcessInventoryForArriving(client);
143 }
144 }
145 }
146 }
147 }
148
149 protected void TeleportStart(IClientAPI client, GridRegion destination, GridRegion finalDestination, uint teleportFlags, bool gridLogout)
150 {
151 if (gridLogout && m_RestrictInventoryAccessAbroad)
152 {
153 IUserManagement uMan = m_Scene.RequestModuleInterface<IUserManagement>();
154 if (uMan != null && uMan.IsLocalGridUser(client.AgentId))
155 {
156 // local grid user
157 ProcessInventoryForHypergriding(client);
158 }
159 else
160 {
161 // Foreigner
162 ProcessInventoryForLeaving(client);
163 }
164 }
165
166 }
167
168 protected void TeleportFail(IClientAPI client, bool gridLogout)
169 {
170 if (gridLogout && m_RestrictInventoryAccessAbroad)
171 {
172 IUserManagement uMan = m_Scene.RequestModuleInterface<IUserManagement>();
173 if (uMan.IsLocalGridUser(client.AgentId))
174 {
175 ProcessInventoryForComingHome(client);
176 }
177 else
178 {
179 ProcessInventoryForArriving(client);
180 }
181 }
182 }
183
115 public void UploadInventoryItem(UUID avatarID, UUID assetID, string name, int userlevel) 184 public void UploadInventoryItem(UUID avatarID, UUID assetID, string name, int userlevel)
116 { 185 {
117 string userAssetServer = string.Empty; 186 string userAssetServer = string.Empty;
@@ -236,8 +305,6 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
236 return false; 305 return false;
237 } 306 }
238 307
239 #endregion
240
241 protected override InventoryItemBase GetItem(UUID agentID, UUID itemID) 308 protected override InventoryItemBase GetItem(UUID agentID, UUID itemID)
242 { 309 {
243 InventoryItemBase item = base.GetItem(agentID, itemID); 310 InventoryItemBase item = base.GetItem(agentID, itemID);
@@ -248,5 +315,84 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
248 315
249 return item; 316 return item;
250 } 317 }
318
319 #endregion
320
321 #region Inventory manipulation upon arriving/leaving
322
323 //
324 // These 2 are for local and foreign users coming back, respectively
325 //
326
327 private void ProcessInventoryForComingHome(IClientAPI client)
328 {
329 m_log.DebugFormat("[HG INVENTORY ACCESS MODULE]: Restoring root folder for local user {0}", client.Name);
330 if (client is IClientCore)
331 {
332 IClientCore core = (IClientCore)client;
333 IClientInventory inv;
334
335 if (core.TryGet<IClientInventory>(out inv))
336 {
337 InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId);
338 InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID);
339
340 inv.SendBulkUpdateInventory(content.Folders.ToArray(), content.Items.ToArray());
341 }
342 }
343 }
344
345 private void ProcessInventoryForArriving(IClientAPI client)
346 {
347 }
348
349 //
350 // These 2 are for local and foreign users going away respectively
351 //
352
353 private void ProcessInventoryForHypergriding(IClientAPI client)
354 {
355 if (client is IClientCore)
356 {
357 IClientCore core = (IClientCore)client;
358 IClientInventory inv;
359
360 if (core.TryGet<IClientInventory>(out inv))
361 {
362 InventoryFolderBase root = m_Scene.InventoryService.GetRootFolder(client.AgentId);
363 if (root != null)
364 {
365 m_log.DebugFormat("[HG INVENTORY ACCESS MODULE]: Changing root inventory for user {0}", client.Name);
366 InventoryCollection content = m_Scene.InventoryService.GetFolderContent(client.AgentId, root.ID);
367 List<UUID> fids = new List<UUID>();
368 List<UUID> iids = new List<UUID>();
369 List<InventoryFolderBase> keep = new List<InventoryFolderBase>();
370
371 foreach (InventoryFolderBase f in content.Folders)
372 {
373 if (f.Name != "My Suitcase")
374 {
375 f.Name = f.Name + " (Unavailable)";
376 keep.Add(f);
377 }
378 }
379
380 // items directly under the root folder
381 foreach (InventoryItemBase it in content.Items)
382 it.Name = it.Name + " (Unavailable)"; ;
383
384 // Send the new names
385 inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray());
386
387 }
388 }
389 }
390 }
391
392 private void ProcessInventoryForLeaving(IClientAPI client)
393 {
394 }
395
396 #endregion
251 } 397 }
252} 398}
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index fe3438e..b3debb0 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -502,6 +502,12 @@ namespace OpenSim.Region.Framework.Scenes
502 public delegate void PrimsLoaded(Scene s); 502 public delegate void PrimsLoaded(Scene s);
503 public event PrimsLoaded OnPrimsLoaded; 503 public event PrimsLoaded OnPrimsLoaded;
504 504
505 public delegate void TeleportStart(IClientAPI client, GridRegion destination, GridRegion finalDestination, uint teleportFlags, bool gridLogout);
506 public event TeleportStart OnTeleportStart;
507
508 public delegate void TeleportFail(IClientAPI client, bool gridLogout);
509 public event TeleportFail OnTeleportFail;
510
505 public class MoneyTransferArgs : EventArgs 511 public class MoneyTransferArgs : EventArgs
506 { 512 {
507 public UUID sender; 513 public UUID sender;
@@ -2463,5 +2469,48 @@ namespace OpenSim.Region.Framework.Scenes
2463 } 2469 }
2464 } 2470 }
2465 } 2471 }
2472
2473 public void TriggerTeleportStart(IClientAPI client, GridRegion destination, GridRegion finalDestination, uint teleportFlags, bool gridLogout)
2474 {
2475 TeleportStart handler = OnTeleportStart;
2476
2477 if (handler != null)
2478 {
2479 foreach (TeleportStart d in handler.GetInvocationList())
2480 {
2481 try
2482 {
2483 d(client, destination, finalDestination, teleportFlags, gridLogout);
2484 }
2485 catch (Exception e)
2486 {
2487 m_log.ErrorFormat("[EVENT MANAGER]: Delegate for TeleportStart failed - continuing {0} - {1}",
2488 e.Message, e.StackTrace);
2489 }
2490 }
2491 }
2492 }
2493
2494 public void TriggerTeleportFail(IClientAPI client, bool gridLogout)
2495 {
2496 TeleportFail handler = OnTeleportFail;
2497
2498 if (handler != null)
2499 {
2500 foreach (TeleportFail d in handler.GetInvocationList())
2501 {
2502 try
2503 {
2504 d(client, gridLogout);
2505 }
2506 catch (Exception e)
2507 {
2508 m_log.ErrorFormat("[EVENT MANAGER]: Delegate for TeleportFail failed - continuing {0} - {1}",
2509 e.Message, e.StackTrace);
2510 }
2511 }
2512 }
2513 }
2514
2466 } 2515 }
2467} 2516}