diff options
author | Teravus Ovares | 2008-01-20 23:08:50 +0000 |
---|---|---|
committer | Teravus Ovares | 2008-01-20 23:08:50 +0000 |
commit | a3851b3812aae6221714b1e61656d0853fce7124 (patch) | |
tree | 8867b4d6c433b0230f276f88a95625695fb71390 /OpenSim | |
parent | Graceful failure of teleport to unavailable regions might actually work now. (diff) | |
download | opensim-SC_OLD-a3851b3812aae6221714b1e61656d0853fce7124.zip opensim-SC_OLD-a3851b3812aae6221714b1e61656d0853fce7124.tar.gz opensim-SC_OLD-a3851b3812aae6221714b1e61656d0853fce7124.tar.bz2 opensim-SC_OLD-a3851b3812aae6221714b1e61656d0853fce7124.tar.xz |
* Added hooks for logout to all IUserService and all that implement it.
* Added a Logout message with a name on the console
* Added a *fixme* message to figure out why the current agent session is null
* After updating you may notice that there's a login <user> and also a logout<user>
Diffstat (limited to 'OpenSim')
-rw-r--r-- | OpenSim/Framework/Communications/CommunicationsManager.cs | 13 | ||||
-rw-r--r-- | OpenSim/Framework/Communications/UserManagerBase.cs | 37 | ||||
-rw-r--r-- | OpenSim/Framework/Data.DB4o/DB4oUserData.cs | 5 | ||||
-rw-r--r-- | OpenSim/Framework/Data.MSSQL/MSSQLUserData.cs | 5 | ||||
-rw-r--r-- | OpenSim/Framework/Data.MySQL/MySQLUserData.cs | 4 | ||||
-rw-r--r-- | OpenSim/Framework/Data.SQLite/SQLiteRegionData.cs | 6 | ||||
-rw-r--r-- | OpenSim/Framework/Data.SQLite/SQLiteUserData.cs | 4 | ||||
-rw-r--r-- | OpenSim/Framework/IUserData.cs | 6 | ||||
-rw-r--r-- | OpenSim/Framework/IUserService.cs | 10 | ||||
-rw-r--r-- | OpenSim/Grid/MessagingServer/MessageService.cs | 2 | ||||
-rw-r--r-- | OpenSim/Grid/UserServer/Main.cs | 1 | ||||
-rw-r--r-- | OpenSim/Grid/UserServer/UserManager.cs | 37 | ||||
-rw-r--r-- | OpenSim/Region/Communications/OGS1/OGS1GridServices.cs | 3 | ||||
-rw-r--r-- | OpenSim/Region/Communications/OGS1/OGS1UserServices.cs | 26 | ||||
-rw-r--r-- | OpenSim/Region/Environment/Scenes/Scene.cs | 3 |
15 files changed, 135 insertions, 27 deletions
diff --git a/OpenSim/Framework/Communications/CommunicationsManager.cs b/OpenSim/Framework/Communications/CommunicationsManager.cs index a07b165..baf24f0 100644 --- a/OpenSim/Framework/Communications/CommunicationsManager.cs +++ b/OpenSim/Framework/Communications/CommunicationsManager.cs | |||
@@ -163,6 +163,19 @@ namespace OpenSim.Framework.Communications | |||
163 | { | 163 | { |
164 | m_userService.AddNewUserFriend(friendlistowner, friend, perms); | 164 | m_userService.AddNewUserFriend(friendlistowner, friend, perms); |
165 | } | 165 | } |
166 | /// <summary> | ||
167 | /// Logs off a user and does the appropriate communications | ||
168 | /// </summary> | ||
169 | /// <param name="userid"></param> | ||
170 | /// <param name="regionid"></param> | ||
171 | /// <param name="regionhandle"></param> | ||
172 | /// <param name="posx"></param> | ||
173 | /// <param name="posy"></param> | ||
174 | /// <param name="posz"></param> | ||
175 | public void LogOffUser(LLUUID userid, LLUUID regionid, ulong regionhandle, float posx, float posy, float posz) | ||
176 | { | ||
177 | m_userService.LogOffUser(userid, regionid, regionhandle, posx, posy, posz); | ||
178 | } | ||
166 | 179 | ||
167 | /// <summary> | 180 | /// <summary> |
168 | /// Delete friend on friendlistowner's friendlist. | 181 | /// Delete friend on friendlistowner's friendlist. |
diff --git a/OpenSim/Framework/Communications/UserManagerBase.cs b/OpenSim/Framework/Communications/UserManagerBase.cs index 4216553..8821776 100644 --- a/OpenSim/Framework/Communications/UserManagerBase.cs +++ b/OpenSim/Framework/Communications/UserManagerBase.cs | |||
@@ -411,7 +411,44 @@ namespace OpenSim.Framework.UserManagement | |||
411 | 411 | ||
412 | profile.currentAgent = agent; | 412 | profile.currentAgent = agent; |
413 | } | 413 | } |
414 | public void LogOffUser(LLUUID userid, LLUUID regionid, ulong regionhandle, float posx, float posy, float posz) | ||
415 | { | ||
416 | UserProfileData userProfile; | ||
417 | UserAgentData userAgent; | ||
418 | LLVector3 currentPos = new LLVector3(posx, posy, posz); | ||
419 | |||
420 | userProfile = GetUserProfile(userid); | ||
421 | |||
422 | if (userProfile != null) | ||
423 | { | ||
424 | |||
425 | userAgent = userProfile.currentAgent; | ||
426 | if (userAgent != null) | ||
427 | { | ||
428 | userAgent.agentOnline = false; | ||
429 | userAgent.logoutTime = Util.UnixTimeSinceEpoch(); | ||
430 | userAgent.sessionID = LLUUID.Zero; | ||
431 | userAgent.currentRegion = regionid; | ||
432 | userAgent.currentHandle = regionhandle; | ||
433 | |||
434 | userAgent.currentPos = currentPos; | ||
435 | |||
436 | userProfile.currentAgent = userAgent; | ||
437 | |||
414 | 438 | ||
439 | CommitAgent(ref userProfile); | ||
440 | } | ||
441 | else | ||
442 | { | ||
443 | MainLog.Instance.Verbose("LOGOUT", "didn't save logout position, currentAgent is null *do Fix "); | ||
444 | } | ||
445 | MainLog.Instance.Verbose("LOGOUT", userProfile.username + " " + userProfile.surname); | ||
446 | } | ||
447 | else | ||
448 | { | ||
449 | MainLog.Instance.Warn("LOGOUT", "Unknown User logged out"); | ||
450 | } | ||
451 | } | ||
415 | public void CreateAgent(UserProfileData profile, LLSD request) | 452 | public void CreateAgent(UserProfileData profile, LLSD request) |
416 | { | 453 | { |
417 | UserAgentData agent = new UserAgentData(); | 454 | UserAgentData agent = new UserAgentData(); |
diff --git a/OpenSim/Framework/Data.DB4o/DB4oUserData.cs b/OpenSim/Framework/Data.DB4o/DB4oUserData.cs index 47521e4..6059cbe 100644 --- a/OpenSim/Framework/Data.DB4o/DB4oUserData.cs +++ b/OpenSim/Framework/Data.DB4o/DB4oUserData.cs | |||
@@ -169,10 +169,7 @@ namespace OpenSim.Framework.Data.DB4o | |||
169 | //MainLog.Instance.Verbose("USER", "Stub UpdateUserCUrrentRegion called"); | 169 | //MainLog.Instance.Verbose("USER", "Stub UpdateUserCUrrentRegion called"); |
170 | } | 170 | } |
171 | 171 | ||
172 | public void LogOffUser(LLUUID avatarid) | 172 | |
173 | { | ||
174 | //MainLog.Instance.Verbose("USER", "Stub LogOffUser called"); | ||
175 | } | ||
176 | 173 | ||
177 | public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query) | 174 | public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query) |
178 | { | 175 | { |
diff --git a/OpenSim/Framework/Data.MSSQL/MSSQLUserData.cs b/OpenSim/Framework/Data.MSSQL/MSSQLUserData.cs index 429ed39..aa0526c 100644 --- a/OpenSim/Framework/Data.MSSQL/MSSQLUserData.cs +++ b/OpenSim/Framework/Data.MSSQL/MSSQLUserData.cs | |||
@@ -129,10 +129,7 @@ namespace OpenSim.Framework.Data.MSSQL | |||
129 | MainLog.Instance.Verbose("USER", "Stub UpdateUserCUrrentRegion called"); | 129 | MainLog.Instance.Verbose("USER", "Stub UpdateUserCUrrentRegion called"); |
130 | } | 130 | } |
131 | 131 | ||
132 | public void LogOffUser(LLUUID avatarid) | 132 | |
133 | { | ||
134 | MainLog.Instance.Verbose("USER", "Stub LogOffUser called"); | ||
135 | } | ||
136 | 133 | ||
137 | public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query) | 134 | public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query) |
138 | { | 135 | { |
diff --git a/OpenSim/Framework/Data.MySQL/MySQLUserData.cs b/OpenSim/Framework/Data.MySQL/MySQLUserData.cs index f637db6..2ee20e0 100644 --- a/OpenSim/Framework/Data.MySQL/MySQLUserData.cs +++ b/OpenSim/Framework/Data.MySQL/MySQLUserData.cs | |||
@@ -331,10 +331,6 @@ namespace OpenSim.Framework.Data.MySQL | |||
331 | MainLog.Instance.Verbose("USER", "Stub UpdateUserCUrrentRegion called"); | 331 | MainLog.Instance.Verbose("USER", "Stub UpdateUserCUrrentRegion called"); |
332 | } | 332 | } |
333 | 333 | ||
334 | public void LogOffUser(LLUUID avatarid) | ||
335 | { | ||
336 | MainLog.Instance.Verbose("USER", "Stub LogOffUser called"); | ||
337 | } | ||
338 | 334 | ||
339 | public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query) | 335 | public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query) |
340 | { | 336 | { |
diff --git a/OpenSim/Framework/Data.SQLite/SQLiteRegionData.cs b/OpenSim/Framework/Data.SQLite/SQLiteRegionData.cs index 1364d3e..2e22f00 100644 --- a/OpenSim/Framework/Data.SQLite/SQLiteRegionData.cs +++ b/OpenSim/Framework/Data.SQLite/SQLiteRegionData.cs | |||
@@ -188,9 +188,9 @@ namespace OpenSim.Framework.Data.SQLite | |||
188 | } | 188 | } |
189 | else if (prim.Stopped) | 189 | else if (prim.Stopped) |
190 | { | 190 | { |
191 | MainLog.Instance.Verbose("DATASTORE", | 191 | //MainLog.Instance.Verbose("DATASTORE", |
192 | "Adding stopped obj: " + obj.UUID + " to region: " + regionUUID); | 192 | //"Adding stopped obj: " + obj.UUID + " to region: " + regionUUID); |
193 | addPrim(prim, Util.ToRawUuidString(obj.UUID), Util.ToRawUuidString(regionUUID)); | 193 | //addPrim(prim, Util.ToRawUuidString(obj.UUID), Util.ToRawUuidString(regionUUID)); |
194 | } | 194 | } |
195 | else | 195 | else |
196 | { | 196 | { |
diff --git a/OpenSim/Framework/Data.SQLite/SQLiteUserData.cs b/OpenSim/Framework/Data.SQLite/SQLiteUserData.cs index ed8275e..ac7340d 100644 --- a/OpenSim/Framework/Data.SQLite/SQLiteUserData.cs +++ b/OpenSim/Framework/Data.SQLite/SQLiteUserData.cs | |||
@@ -234,10 +234,6 @@ namespace OpenSim.Framework.Data.SQLite | |||
234 | MainLog.Instance.Verbose("USER", "Stub UpdateUserCUrrentRegion called"); | 234 | MainLog.Instance.Verbose("USER", "Stub UpdateUserCUrrentRegion called"); |
235 | } | 235 | } |
236 | 236 | ||
237 | public void LogOffUser(LLUUID avatarid) | ||
238 | { | ||
239 | MainLog.Instance.Verbose("USER", "Stub LogOffUser called"); | ||
240 | } | ||
241 | 237 | ||
242 | public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query) | 238 | public List<Framework.AvatarPickerAvatar> GeneratePickerResults(LLUUID queryID, string query) |
243 | { | 239 | { |
diff --git a/OpenSim/Framework/IUserData.cs b/OpenSim/Framework/IUserData.cs index 9fd6fa8..45ba7fa 100644 --- a/OpenSim/Framework/IUserData.cs +++ b/OpenSim/Framework/IUserData.cs | |||
@@ -106,12 +106,6 @@ namespace OpenSim.Framework | |||
106 | void UpdateUserCurrentRegion(LLUUID avatarid, LLUUID regionuuid); | 106 | void UpdateUserCurrentRegion(LLUUID avatarid, LLUUID regionuuid); |
107 | 107 | ||
108 | /// <summary> | 108 | /// <summary> |
109 | /// Log User Off | ||
110 | /// </summary> | ||
111 | /// <param name="avatarid">avatar to log off</param> | ||
112 | void LogOffUser(LLUUID avatarid); | ||
113 | |||
114 | /// <summary> | ||
115 | /// Adds a new agent to the database | 109 | /// Adds a new agent to the database |
116 | /// </summary> | 110 | /// </summary> |
117 | /// <param name="agent">The agent to add</param> | 111 | /// <param name="agent">The agent to add</param> |
diff --git a/OpenSim/Framework/IUserService.cs b/OpenSim/Framework/IUserService.cs index 2b59c25..f1f3c81 100644 --- a/OpenSim/Framework/IUserService.cs +++ b/OpenSim/Framework/IUserService.cs | |||
@@ -73,6 +73,16 @@ namespace OpenSim.Framework | |||
73 | void UpdateUserFriendPerms(LLUUID friendlistowner, LLUUID friend, uint perms); | 73 | void UpdateUserFriendPerms(LLUUID friendlistowner, LLUUID friend, uint perms); |
74 | 74 | ||
75 | /// <summary> | 75 | /// <summary> |
76 | /// Logs off a user on the user server | ||
77 | /// </summary> | ||
78 | /// <param name="UserID">UUID of the user</param> | ||
79 | /// <param name="regionData">UUID of the Region</param> | ||
80 | /// <param name="posx">final position x</param> | ||
81 | /// <param name="posy">final position y</param> | ||
82 | /// <param name="posz">final position z</param> | ||
83 | void LogOffUser(LLUUID userid, LLUUID regionid, ulong regionhandle, float posx, float posy, float posz); | ||
84 | |||
85 | /// <summary> | ||
76 | /// Returns a list of FriendsListItems that describe the friends and permissions in the friend relationship for LLUUID friendslistowner | 86 | /// Returns a list of FriendsListItems that describe the friends and permissions in the friend relationship for LLUUID friendslistowner |
77 | /// </summary> | 87 | /// </summary> |
78 | /// <param name="friendlistowner">The agent that we're retreiving the friends Data.</param> | 88 | /// <param name="friendlistowner">The agent that we're retreiving the friends Data.</param> |
diff --git a/OpenSim/Grid/MessagingServer/MessageService.cs b/OpenSim/Grid/MessagingServer/MessageService.cs index 01bd9af..056bfcb 100644 --- a/OpenSim/Grid/MessagingServer/MessageService.cs +++ b/OpenSim/Grid/MessagingServer/MessageService.cs | |||
@@ -388,7 +388,7 @@ namespace OpenSim.Grid.MessagingServer | |||
388 | LLUUID AgentID = new LLUUID((string)requestData["agent_id"]); | 388 | LLUUID AgentID = new LLUUID((string)requestData["agent_id"]); |
389 | 389 | ||
390 | 390 | ||
391 | ProcessLogOff(AgentID); | 391 | //ProcessLogOff(AgentID); |
392 | 392 | ||
393 | 393 | ||
394 | return new XmlRpcResponse(); | 394 | return new XmlRpcResponse(); |
diff --git a/OpenSim/Grid/UserServer/Main.cs b/OpenSim/Grid/UserServer/Main.cs index 00a1641..a2881e6 100644 --- a/OpenSim/Grid/UserServer/Main.cs +++ b/OpenSim/Grid/UserServer/Main.cs | |||
@@ -115,6 +115,7 @@ namespace OpenSim.Grid.UserServer | |||
115 | httpServer.AddXmlRPCHandler("remove_user_friend", m_userManager.XmlRpcResponseXmlRPCRemoveUserFriend); | 115 | httpServer.AddXmlRPCHandler("remove_user_friend", m_userManager.XmlRpcResponseXmlRPCRemoveUserFriend); |
116 | httpServer.AddXmlRPCHandler("update_user_friend_perms", m_userManager.XmlRpcResponseXmlRPCUpdateUserFriendPerms); | 116 | httpServer.AddXmlRPCHandler("update_user_friend_perms", m_userManager.XmlRpcResponseXmlRPCUpdateUserFriendPerms); |
117 | httpServer.AddXmlRPCHandler("get_user_friend_list", m_userManager.XmlRpcResponseXmlRPCGetUserFriendList); | 117 | httpServer.AddXmlRPCHandler("get_user_friend_list", m_userManager.XmlRpcResponseXmlRPCGetUserFriendList); |
118 | httpServer.AddXmlRPCHandler("logout_of_simulator", m_userManager.XmlRPCLogOffUserMethodUUID); | ||
118 | 119 | ||
119 | // Message Server ---> User Server | 120 | // Message Server ---> User Server |
120 | httpServer.AddXmlRPCHandler("register_messageserver", m_messagesService.XmlRPCRegisterMessageServer); | 121 | httpServer.AddXmlRPCHandler("register_messageserver", m_messagesService.XmlRPCRegisterMessageServer); |
diff --git a/OpenSim/Grid/UserServer/UserManager.cs b/OpenSim/Grid/UserServer/UserManager.cs index 03b1fbc..3f2aa5b 100644 --- a/OpenSim/Grid/UserServer/UserManager.cs +++ b/OpenSim/Grid/UserServer/UserManager.cs | |||
@@ -317,6 +317,43 @@ namespace OpenSim.Grid.UserServer | |||
317 | return ProfileToXmlRPCResponse(userProfile); | 317 | return ProfileToXmlRPCResponse(userProfile); |
318 | } | 318 | } |
319 | 319 | ||
320 | public XmlRpcResponse XmlRPCLogOffUserMethodUUID(XmlRpcRequest request) | ||
321 | { | ||
322 | XmlRpcResponse response = new XmlRpcResponse(); | ||
323 | Hashtable requestData = (Hashtable)request.Params[0]; | ||
324 | |||
325 | |||
326 | UserProfileData userProfile; | ||
327 | |||
328 | if (requestData.Contains("avatar_uuid")) | ||
329 | { | ||
330 | try | ||
331 | { | ||
332 | LLUUID userUUID = new LLUUID((string)requestData["avatar_uuid"]); | ||
333 | LLUUID RegionID = new LLUUID((string)requestData["region_uuid"]); | ||
334 | ulong regionhandle = (ulong)Convert.ToInt64((string)requestData["region_handle"]); | ||
335 | float posx = (float)Convert.ToDecimal((string)requestData["region_pos_x"]); | ||
336 | float posy = (float)Convert.ToDecimal((string)requestData["region_pos_y"]); | ||
337 | float posz = (float)Convert.ToDecimal((string)requestData["region_pos_z"]); | ||
338 | |||
339 | LogOffUser(userUUID, RegionID, regionhandle, posx, posy, posz); | ||
340 | } | ||
341 | catch (FormatException) | ||
342 | { | ||
343 | OpenSim.Framework.Console.MainLog.Instance.Warn("LOGOUT", "Error in Logout XMLRPC Params"); | ||
344 | return response; | ||
345 | } | ||
346 | |||
347 | } | ||
348 | else | ||
349 | { | ||
350 | return CreateUnknownUserErrorResponse(); | ||
351 | } | ||
352 | |||
353 | |||
354 | return response; | ||
355 | } | ||
356 | |||
320 | #endregion | 357 | #endregion |
321 | 358 | ||
322 | public override UserProfileData SetupMasterUser(string firstName, string lastName) | 359 | public override UserProfileData SetupMasterUser(string firstName, string lastName) |
diff --git a/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs b/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs index 7cd77db..2ca9022 100644 --- a/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs +++ b/OpenSim/Region/Communications/OGS1/OGS1GridServices.cs | |||
@@ -375,6 +375,9 @@ namespace OpenSim.Region.Communications.OGS1 | |||
375 | return neighbours; | 375 | return neighbours; |
376 | } | 376 | } |
377 | 377 | ||
378 | |||
379 | |||
380 | |||
378 | /// <summary> | 381 | /// <summary> |
379 | /// Performs a XML-RPC query against the grid server returning mapblock information in the specified coordinates | 382 | /// Performs a XML-RPC query against the grid server returning mapblock information in the specified coordinates |
380 | /// </summary> | 383 | /// </summary> |
diff --git a/OpenSim/Region/Communications/OGS1/OGS1UserServices.cs b/OpenSim/Region/Communications/OGS1/OGS1UserServices.cs index 36ab4bb..2cf3665 100644 --- a/OpenSim/Region/Communications/OGS1/OGS1UserServices.cs +++ b/OpenSim/Region/Communications/OGS1/OGS1UserServices.cs | |||
@@ -130,7 +130,31 @@ namespace OpenSim.Region.Communications.OGS1 | |||
130 | 130 | ||
131 | return buddylist; | 131 | return buddylist; |
132 | } | 132 | } |
133 | 133 | ||
134 | /// <summary> | ||
135 | /// Logs off a user on the user server | ||
136 | /// </summary> | ||
137 | /// <param name="UserID">UUID of the user</param> | ||
138 | /// <param name="regionData">UUID of the Region</param> | ||
139 | /// <param name="posx">final position x</param> | ||
140 | /// <param name="posy">final position y</param> | ||
141 | /// <param name="posz">final position z</param> | ||
142 | public void LogOffUser(LLUUID userid, LLUUID regionid, ulong regionhandle, float posx, float posy, float posz) | ||
143 | { | ||
144 | Hashtable param = new Hashtable(); | ||
145 | param["avatar_uuid"] = userid.UUID.ToString(); | ||
146 | param["region_uuid"] = regionid.UUID.ToString(); | ||
147 | param["region_handle"] = regionhandle.ToString(); | ||
148 | param["region_pos_x"] = posx.ToString(); | ||
149 | param["region_pos_y"] = posy.ToString(); | ||
150 | param["region_pos_z"] = posz.ToString(); | ||
151 | |||
152 | IList parameters = new ArrayList(); | ||
153 | parameters.Add(param); | ||
154 | XmlRpcRequest req = new XmlRpcRequest("logout_of_simulator", parameters); | ||
155 | XmlRpcResponse resp = req.Send(m_parent.NetworkServersInfo.UserURL, 3000); | ||
156 | |||
157 | } | ||
134 | public UserProfileData GetUserProfile(string firstName, string lastName) | 158 | public UserProfileData GetUserProfile(string firstName, string lastName) |
135 | { | 159 | { |
136 | return GetUserProfile(firstName + " " + lastName); | 160 | return GetUserProfile(firstName + " " + lastName); |
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 76f6c60..2f961c1 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs | |||
@@ -1285,6 +1285,9 @@ namespace OpenSim.Region.Environment.Scenes | |||
1285 | else | 1285 | else |
1286 | { | 1286 | { |
1287 | m_innerScene.removeUserCount(true); | 1287 | m_innerScene.removeUserCount(true); |
1288 | CommsManager.LogOffUser(agentID, RegionInfo.RegionID, RegionInfo.RegionHandle, | ||
1289 | avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, | ||
1290 | avatar.AbsolutePosition.Z); | ||
1288 | } | 1291 | } |
1289 | } | 1292 | } |
1290 | catch (NullReferenceException) | 1293 | catch (NullReferenceException) |