diff options
Start of the OpenSim library , for now only contains a few textures.
Diffstat (limited to 'OpenSim/Framework/Communications/Cache/AssetTransactions.cs')
-rw-r--r-- | OpenSim/Framework/Communications/Cache/AssetTransactions.cs | 548 |
1 files changed, 274 insertions, 274 deletions
diff --git a/OpenSim/Framework/Communications/Cache/AssetTransactions.cs b/OpenSim/Framework/Communications/Cache/AssetTransactions.cs index 6741969..c906b76 100644 --- a/OpenSim/Framework/Communications/Cache/AssetTransactions.cs +++ b/OpenSim/Framework/Communications/Cache/AssetTransactions.cs | |||
@@ -1,275 +1,275 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://www.openmetaverse.org/ | 2 | * Copyright (c) Contributors, http://www.openmetaverse.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSim Project nor the | 12 | * * Neither the name of the OpenSim Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * | 26 | * |
27 | */ | 27 | */ |
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Text; | 31 | using System.Text; |
32 | using System.IO; | 32 | using System.IO; |
33 | using libsecondlife; | 33 | using libsecondlife; |
34 | using libsecondlife.Packets; | 34 | using libsecondlife.Packets; |
35 | using OpenSim.Framework.Interfaces; | 35 | using OpenSim.Framework.Interfaces; |
36 | using OpenSim.Framework.Types; | 36 | using OpenSim.Framework.Types; |
37 | using OpenSim.Framework.Utilities; | 37 | using OpenSim.Framework.Utilities; |
38 | using OpenSim.Region.Capabilities; | 38 | using OpenSim.Region.Capabilities; |
39 | using OpenSim.Framework.Servers; | 39 | using OpenSim.Framework.Servers; |
40 | 40 | ||
41 | namespace OpenSim.Framework.Communications.Caches | 41 | namespace OpenSim.Framework.Communications.Caches |
42 | { | 42 | { |
43 | public class AgentAssetTransactions | 43 | public class AgentAssetTransactions |
44 | { | 44 | { |
45 | // Fields | 45 | // Fields |
46 | public List<AssetCapsUploader> CapsUploaders = new List<AssetCapsUploader>(); | 46 | public List<AssetCapsUploader> CapsUploaders = new List<AssetCapsUploader>(); |
47 | public List<NoteCardCapsUpdate> NotecardUpdaters = new List<NoteCardCapsUpdate>(); | 47 | public List<NoteCardCapsUpdate> NotecardUpdaters = new List<NoteCardCapsUpdate>(); |
48 | public LLUUID UserID; | 48 | public LLUUID UserID; |
49 | public Dictionary<LLUUID, AssetXferUploader> XferUploaders = new Dictionary<LLUUID, AssetXferUploader>(); | 49 | public Dictionary<LLUUID, AssetXferUploader> XferUploaders = new Dictionary<LLUUID, AssetXferUploader>(); |
50 | 50 | ||
51 | // Methods | 51 | // Methods |
52 | public AgentAssetTransactions(LLUUID agentID) | 52 | public AgentAssetTransactions(LLUUID agentID) |
53 | { | 53 | { |
54 | this.UserID = agentID; | 54 | this.UserID = agentID; |
55 | } | 55 | } |
56 | 56 | ||
57 | public AssetCapsUploader RequestCapsUploader() | 57 | public AssetCapsUploader RequestCapsUploader() |
58 | { | 58 | { |
59 | AssetCapsUploader uploader = new AssetCapsUploader(); | 59 | AssetCapsUploader uploader = new AssetCapsUploader(); |
60 | this.CapsUploaders.Add(uploader); | 60 | this.CapsUploaders.Add(uploader); |
61 | return uploader; | 61 | return uploader; |
62 | } | 62 | } |
63 | 63 | ||
64 | public NoteCardCapsUpdate RequestNoteCardUpdater() | 64 | public NoteCardCapsUpdate RequestNoteCardUpdater() |
65 | { | 65 | { |
66 | NoteCardCapsUpdate update = new NoteCardCapsUpdate(); | 66 | NoteCardCapsUpdate update = new NoteCardCapsUpdate(); |
67 | this.NotecardUpdaters.Add(update); | 67 | this.NotecardUpdaters.Add(update); |
68 | return update; | 68 | return update; |
69 | } | 69 | } |
70 | 70 | ||
71 | public AssetXferUploader RequestXferUploader(LLUUID transactionID) | 71 | public AssetXferUploader RequestXferUploader(LLUUID transactionID) |
72 | { | 72 | { |
73 | AssetXferUploader uploader = new AssetXferUploader(); | 73 | AssetXferUploader uploader = new AssetXferUploader(); |
74 | this.XferUploaders.Add(transactionID, uploader); | 74 | this.XferUploaders.Add(transactionID, uploader); |
75 | return uploader; | 75 | return uploader; |
76 | } | 76 | } |
77 | 77 | ||
78 | // Nested Types | 78 | // Nested Types |
79 | public class AssetCapsUploader | 79 | public class AssetCapsUploader |
80 | { | 80 | { |
81 | // Fields | 81 | // Fields |
82 | private BaseHttpServer httpListener; | 82 | private BaseHttpServer httpListener; |
83 | private LLUUID inventoryItemID; | 83 | private LLUUID inventoryItemID; |
84 | private string m_assetDescription = ""; | 84 | private string m_assetDescription = ""; |
85 | private string m_assetName = ""; | 85 | private string m_assetName = ""; |
86 | private LLUUID m_folderID; | 86 | private LLUUID m_folderID; |
87 | private LLUUID newAssetID; | 87 | private LLUUID newAssetID; |
88 | private bool SaveImages = false; | 88 | private bool SaveImages = false; |
89 | private string uploaderPath = ""; | 89 | private string uploaderPath = ""; |
90 | 90 | ||
91 | // Events | 91 | // Events |
92 | public event UpLoadedTexture OnUpLoad; | 92 | public event UpLoadedTexture OnUpLoad; |
93 | 93 | ||
94 | // Methods | 94 | // Methods |
95 | public void Initialise(string assetName, string assetDescription, LLUUID assetID, LLUUID inventoryItem, LLUUID folderID, string path, BaseHttpServer httpServer) | 95 | public void Initialise(string assetName, string assetDescription, LLUUID assetID, LLUUID inventoryItem, LLUUID folderID, string path, BaseHttpServer httpServer) |
96 | { | 96 | { |
97 | this.m_assetName = assetName; | 97 | this.m_assetName = assetName; |
98 | this.m_assetDescription = assetDescription; | 98 | this.m_assetDescription = assetDescription; |
99 | this.m_folderID = folderID; | 99 | this.m_folderID = folderID; |
100 | this.newAssetID = assetID; | 100 | this.newAssetID = assetID; |
101 | this.inventoryItemID = inventoryItem; | 101 | this.inventoryItemID = inventoryItem; |
102 | this.uploaderPath = path; | 102 | this.uploaderPath = path; |
103 | this.httpListener = httpServer; | 103 | this.httpListener = httpServer; |
104 | } | 104 | } |
105 | 105 | ||
106 | private void SaveImageToFile(string filename, byte[] data) | 106 | private void SaveImageToFile(string filename, byte[] data) |
107 | { | 107 | { |
108 | FileStream output = File.Create(filename); | 108 | FileStream output = File.Create(filename); |
109 | BinaryWriter writer = new BinaryWriter(output); | 109 | BinaryWriter writer = new BinaryWriter(output); |
110 | writer.Write(data); | 110 | writer.Write(data); |
111 | writer.Close(); | 111 | writer.Close(); |
112 | output.Close(); | 112 | output.Close(); |
113 | } | 113 | } |
114 | 114 | ||
115 | public string uploaderCaps(byte[] data, string path, string param) | 115 | public string uploaderCaps(byte[] data, string path, string param) |
116 | { | 116 | { |
117 | LLUUID inventoryItemID = this.inventoryItemID; | 117 | LLUUID inventoryItemID = this.inventoryItemID; |
118 | string text = ""; | 118 | string text = ""; |
119 | LLSDAssetUploadComplete complete = new LLSDAssetUploadComplete(); | 119 | LLSDAssetUploadComplete complete = new LLSDAssetUploadComplete(); |
120 | complete.new_asset = this.newAssetID.ToStringHyphenated(); | 120 | complete.new_asset = this.newAssetID.ToStringHyphenated(); |
121 | complete.new_inventory_item = inventoryItemID; | 121 | complete.new_inventory_item = inventoryItemID; |
122 | complete.state = "complete"; | 122 | complete.state = "complete"; |
123 | text = LLSDHelpers.SerialiseLLSDReply(complete); | 123 | text = LLSDHelpers.SerialiseLLSDReply(complete); |
124 | this.httpListener.RemoveStreamHandler("POST", this.uploaderPath); | 124 | this.httpListener.RemoveStreamHandler("POST", this.uploaderPath); |
125 | if (this.SaveImages) | 125 | if (this.SaveImages) |
126 | { | 126 | { |
127 | this.SaveImageToFile(this.m_assetName + ".jp2", data); | 127 | this.SaveImageToFile(this.m_assetName + ".jp2", data); |
128 | } | 128 | } |
129 | if (this.OnUpLoad != null) | 129 | if (this.OnUpLoad != null) |
130 | { | 130 | { |
131 | this.OnUpLoad(this.m_assetName, this.newAssetID, inventoryItemID, data); | 131 | this.OnUpLoad(this.m_assetName, this.newAssetID, inventoryItemID, data); |
132 | } | 132 | } |
133 | return text; | 133 | return text; |
134 | } | 134 | } |
135 | } | 135 | } |
136 | 136 | ||
137 | public class AssetXferUploader | 137 | public class AssetXferUploader |
138 | { | 138 | { |
139 | // Fields | 139 | // Fields |
140 | public bool AddToInventory; | 140 | public bool AddToInventory; |
141 | public AssetBase Asset; | 141 | public AssetBase Asset; |
142 | public LLUUID InventFolder = LLUUID.Zero; | 142 | public LLUUID InventFolder = LLUUID.Zero; |
143 | private IClientAPI ourClient; | 143 | private IClientAPI ourClient; |
144 | public LLUUID TransactionID = LLUUID.Zero; | 144 | public LLUUID TransactionID = LLUUID.Zero; |
145 | public bool UploadComplete; | 145 | public bool UploadComplete; |
146 | public uint XferID; | 146 | public uint XferID; |
147 | 147 | ||
148 | // Methods | 148 | // Methods |
149 | public void HandleXferPacket(uint xferID, uint packetID, byte[] data) | 149 | public void HandleXferPacket(uint xferID, uint packetID, byte[] data) |
150 | { | 150 | { |
151 | if (this.XferID == xferID) | 151 | if (this.XferID == xferID) |
152 | { | 152 | { |
153 | if (this.Asset.Data.Length > 1) | 153 | if (this.Asset.Data.Length > 1) |
154 | { | 154 | { |
155 | byte[] destinationArray = new byte[this.Asset.Data.Length + data.Length]; | 155 | byte[] destinationArray = new byte[this.Asset.Data.Length + data.Length]; |
156 | Array.Copy(this.Asset.Data, 0, destinationArray, 0, this.Asset.Data.Length); | 156 | Array.Copy(this.Asset.Data, 0, destinationArray, 0, this.Asset.Data.Length); |
157 | Array.Copy(data, 0, destinationArray, this.Asset.Data.Length, data.Length); | 157 | Array.Copy(data, 0, destinationArray, this.Asset.Data.Length, data.Length); |
158 | this.Asset.Data = destinationArray; | 158 | this.Asset.Data = destinationArray; |
159 | } | 159 | } |
160 | else | 160 | else |
161 | { | 161 | { |
162 | byte[] buffer2 = new byte[data.Length - 4]; | 162 | byte[] buffer2 = new byte[data.Length - 4]; |
163 | Array.Copy(data, 4, buffer2, 0, data.Length - 4); | 163 | Array.Copy(data, 4, buffer2, 0, data.Length - 4); |
164 | this.Asset.Data = buffer2; | 164 | this.Asset.Data = buffer2; |
165 | } | 165 | } |
166 | ConfirmXferPacketPacket newPack = new ConfirmXferPacketPacket(); | 166 | ConfirmXferPacketPacket newPack = new ConfirmXferPacketPacket(); |
167 | newPack.XferID.ID = xferID; | 167 | newPack.XferID.ID = xferID; |
168 | newPack.XferID.Packet = packetID; | 168 | newPack.XferID.Packet = packetID; |
169 | this.ourClient.OutPacket(newPack); | 169 | this.ourClient.OutPacket(newPack); |
170 | if ((packetID & 0x80000000) != 0) | 170 | if ((packetID & 0x80000000) != 0) |
171 | { | 171 | { |
172 | this.SendCompleteMessage(); | 172 | this.SendCompleteMessage(); |
173 | } | 173 | } |
174 | } | 174 | } |
175 | } | 175 | } |
176 | 176 | ||
177 | public void Initialise(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data) | 177 | public void Initialise(IClientAPI remoteClient, LLUUID assetID, LLUUID transaction, sbyte type, byte[] data) |
178 | { | 178 | { |
179 | this.ourClient = remoteClient; | 179 | this.ourClient = remoteClient; |
180 | this.Asset = new AssetBase(); | 180 | this.Asset = new AssetBase(); |
181 | this.Asset.FullID = assetID; | 181 | this.Asset.FullID = assetID; |
182 | this.Asset.InvType = type; | 182 | this.Asset.InvType = type; |
183 | this.Asset.Type = type; | 183 | this.Asset.Type = type; |
184 | this.Asset.Data = data; | 184 | this.Asset.Data = data; |
185 | this.Asset.Name = "blank"; | 185 | this.Asset.Name = "blank"; |
186 | this.Asset.Description = "empty"; | 186 | this.Asset.Description = "empty"; |
187 | this.TransactionID = transaction; | 187 | this.TransactionID = transaction; |
188 | if (this.Asset.Data.Length > 2) | 188 | if (this.Asset.Data.Length > 2) |
189 | { | 189 | { |
190 | this.SendCompleteMessage(); | 190 | this.SendCompleteMessage(); |
191 | } | 191 | } |
192 | else | 192 | else |
193 | { | 193 | { |
194 | this.ReqestStartXfer(); | 194 | this.ReqestStartXfer(); |
195 | } | 195 | } |
196 | } | 196 | } |
197 | 197 | ||
198 | protected void ReqestStartXfer() | 198 | protected void ReqestStartXfer() |
199 | { | 199 | { |
200 | this.UploadComplete = false; | 200 | this.UploadComplete = false; |
201 | this.XferID = Util.GetNextXferID(); | 201 | this.XferID = Util.GetNextXferID(); |
202 | RequestXferPacket newPack = new RequestXferPacket(); | 202 | RequestXferPacket newPack = new RequestXferPacket(); |
203 | newPack.XferID.ID = this.XferID; | 203 | newPack.XferID.ID = this.XferID; |
204 | newPack.XferID.VFileType = this.Asset.Type; | 204 | newPack.XferID.VFileType = this.Asset.Type; |
205 | newPack.XferID.VFileID = this.Asset.FullID; | 205 | newPack.XferID.VFileID = this.Asset.FullID; |
206 | newPack.XferID.FilePath = 0; | 206 | newPack.XferID.FilePath = 0; |
207 | newPack.XferID.Filename = new byte[0]; | 207 | newPack.XferID.Filename = new byte[0]; |
208 | this.ourClient.OutPacket(newPack); | 208 | this.ourClient.OutPacket(newPack); |
209 | } | 209 | } |
210 | 210 | ||
211 | protected void SendCompleteMessage() | 211 | protected void SendCompleteMessage() |
212 | { | 212 | { |
213 | this.UploadComplete = true; | 213 | this.UploadComplete = true; |
214 | AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); | 214 | AssetUploadCompletePacket newPack = new AssetUploadCompletePacket(); |
215 | newPack.AssetBlock.Type = this.Asset.Type; | 215 | newPack.AssetBlock.Type = this.Asset.Type; |
216 | newPack.AssetBlock.Success = true; | 216 | newPack.AssetBlock.Success = true; |
217 | newPack.AssetBlock.UUID = this.Asset.FullID; | 217 | newPack.AssetBlock.UUID = this.Asset.FullID; |
218 | this.ourClient.OutPacket(newPack); | 218 | this.ourClient.OutPacket(newPack); |
219 | } | 219 | } |
220 | } | 220 | } |
221 | 221 | ||
222 | public class NoteCardCapsUpdate | 222 | public class NoteCardCapsUpdate |
223 | { | 223 | { |
224 | // Fields | 224 | // Fields |
225 | private BaseHttpServer httpListener; | 225 | private BaseHttpServer httpListener; |
226 | private LLUUID inventoryItemID; | 226 | private LLUUID inventoryItemID; |
227 | private string m_assetName = ""; | 227 | private string m_assetName = ""; |
228 | private LLUUID newAssetID; | 228 | private LLUUID newAssetID; |
229 | private bool SaveImages = false; | 229 | private bool SaveImages = false; |
230 | private string uploaderPath = ""; | 230 | private string uploaderPath = ""; |
231 | 231 | ||
232 | // Events | 232 | // Events |
233 | public event UpLoadedTexture OnUpLoad; | 233 | public event UpLoadedTexture OnUpLoad; |
234 | 234 | ||
235 | // Methods | 235 | // Methods |
236 | public void Initialise(LLUUID inventoryItem, string path, BaseHttpServer httpServer) | 236 | public void Initialise(LLUUID inventoryItem, string path, BaseHttpServer httpServer) |
237 | { | 237 | { |
238 | this.inventoryItemID = inventoryItem; | 238 | this.inventoryItemID = inventoryItem; |
239 | this.uploaderPath = path; | 239 | this.uploaderPath = path; |
240 | this.httpListener = httpServer; | 240 | this.httpListener = httpServer; |
241 | this.newAssetID = LLUUID.Random(); | 241 | this.newAssetID = LLUUID.Random(); |
242 | } | 242 | } |
243 | 243 | ||
244 | private void SaveImageToFile(string filename, byte[] data) | 244 | private void SaveImageToFile(string filename, byte[] data) |
245 | { | 245 | { |
246 | FileStream output = File.Create(filename); | 246 | FileStream output = File.Create(filename); |
247 | BinaryWriter writer = new BinaryWriter(output); | 247 | BinaryWriter writer = new BinaryWriter(output); |
248 | writer.Write(data); | 248 | writer.Write(data); |
249 | writer.Close(); | 249 | writer.Close(); |
250 | output.Close(); | 250 | output.Close(); |
251 | } | 251 | } |
252 | 252 | ||
253 | public string uploaderCaps(byte[] data, string path, string param) | 253 | public string uploaderCaps(byte[] data, string path, string param) |
254 | { | 254 | { |
255 | LLUUID inventoryItemID = this.inventoryItemID; | 255 | LLUUID inventoryItemID = this.inventoryItemID; |
256 | string text = ""; | 256 | string text = ""; |
257 | LLSDAssetUploadComplete complete = new LLSDAssetUploadComplete(); | 257 | LLSDAssetUploadComplete complete = new LLSDAssetUploadComplete(); |
258 | complete.new_asset = this.newAssetID.ToStringHyphenated(); | 258 | complete.new_asset = this.newAssetID.ToStringHyphenated(); |
259 | complete.new_inventory_item = inventoryItemID; | 259 | complete.new_inventory_item = inventoryItemID; |
260 | complete.state = "complete"; | 260 | complete.state = "complete"; |
261 | text = LLSDHelpers.SerialiseLLSDReply(complete); | 261 | text = LLSDHelpers.SerialiseLLSDReply(complete); |
262 | this.httpListener.RemoveStreamHandler("POST", this.uploaderPath); | 262 | this.httpListener.RemoveStreamHandler("POST", this.uploaderPath); |
263 | if (this.SaveImages) | 263 | if (this.SaveImages) |
264 | { | 264 | { |
265 | this.SaveImageToFile(this.m_assetName + "notecard.txt", data); | 265 | this.SaveImageToFile(this.m_assetName + "notecard.txt", data); |
266 | } | 266 | } |
267 | if (this.OnUpLoad != null) | 267 | if (this.OnUpLoad != null) |
268 | { | 268 | { |
269 | this.OnUpLoad(this.m_assetName, this.newAssetID, inventoryItemID, data); | 269 | this.OnUpLoad(this.m_assetName, this.newAssetID, inventoryItemID, data); |
270 | } | 270 | } |
271 | return text; | 271 | return text; |
272 | } | 272 | } |
273 | } | 273 | } |
274 | } | 274 | } |
275 | } \ No newline at end of file | 275 | } \ No newline at end of file |