diff options
author | Melanie | 2009-08-17 05:00:30 +0100 |
---|---|---|
committer | Melanie | 2009-08-17 05:00:30 +0100 |
commit | 002940dd5dc8a4b5fa23ea6d5183e00431dd48df (patch) | |
tree | 793c49a583cd9f59a7d42c01de017a557e0cac5d | |
parent | * handle litjson errors for now. We'll remove this when we hear back from ... (diff) | |
download | opensim-SC_OLD-002940dd5dc8a4b5fa23ea6d5183e00431dd48df.zip opensim-SC_OLD-002940dd5dc8a4b5fa23ea6d5183e00431dd48df.tar.gz opensim-SC_OLD-002940dd5dc8a4b5fa23ea6d5183e00431dd48df.tar.bz2 opensim-SC_OLD-002940dd5dc8a4b5fa23ea6d5183e00431dd48df.tar.xz |
Filling in the blanks: The "meat" of the REST console
-rw-r--r-- | OpenSim/Framework/Console/CommandConsole.cs | 60 | ||||
-rw-r--r-- | OpenSim/Framework/Console/RemoteConsole.cs | 334 | ||||
-rw-r--r-- | OpenSim/Server/Base/HttpServerBase.cs | 10 | ||||
-rw-r--r-- | prebuild.xml | 2 |
4 files changed, 392 insertions, 14 deletions
diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs index 8b63d01..7af8204 100644 --- a/OpenSim/Framework/Console/CommandConsole.cs +++ b/OpenSim/Framework/Console/CommandConsole.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Xml; | ||
29 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
30 | using System.Diagnostics; | 31 | using System.Diagnostics; |
31 | using System.Reflection; | 32 | using System.Reflection; |
@@ -369,6 +370,65 @@ namespace OpenSim.Framework.Console | |||
369 | 370 | ||
370 | return new string[0]; | 371 | return new string[0]; |
371 | } | 372 | } |
373 | |||
374 | public XmlElement GetXml(XmlDocument doc) | ||
375 | { | ||
376 | XmlElement root = doc.CreateElement("", "HelpTree", ""); | ||
377 | |||
378 | ProcessTreeLevel(tree, root, doc); | ||
379 | |||
380 | return root; | ||
381 | } | ||
382 | |||
383 | private void ProcessTreeLevel(Dictionary<string, object> level, XmlElement xml, XmlDocument doc) | ||
384 | { | ||
385 | foreach (KeyValuePair<string, object> kvp in level) | ||
386 | { | ||
387 | if (kvp.Value is Dictionary<string, Object>) | ||
388 | { | ||
389 | XmlElement next = doc.CreateElement("", "Level", ""); | ||
390 | next.SetAttribute("Name", kvp.Key); | ||
391 | |||
392 | xml.AppendChild(next); | ||
393 | |||
394 | ProcessTreeLevel((Dictionary<string, object>)kvp.Value, next, doc); | ||
395 | } | ||
396 | else | ||
397 | { | ||
398 | CommandInfo c = (CommandInfo)kvp.Value; | ||
399 | |||
400 | XmlElement cmd = doc.CreateElement("", "Command", ""); | ||
401 | |||
402 | XmlElement e; | ||
403 | |||
404 | e = doc.CreateElement("", "Module", ""); | ||
405 | cmd.AppendChild(e); | ||
406 | e.AppendChild(doc.CreateTextNode(c.module)); | ||
407 | |||
408 | e = doc.CreateElement("", "Shared", ""); | ||
409 | cmd.AppendChild(e); | ||
410 | e.AppendChild(doc.CreateTextNode(c.shared.ToString())); | ||
411 | |||
412 | e = doc.CreateElement("", "HelpText", ""); | ||
413 | cmd.AppendChild(e); | ||
414 | e.AppendChild(doc.CreateTextNode(c.help_text)); | ||
415 | |||
416 | e = doc.CreateElement("", "LongHelp", ""); | ||
417 | cmd.AppendChild(e); | ||
418 | e.AppendChild(doc.CreateTextNode(c.long_help)); | ||
419 | |||
420 | e = doc.CreateElement("", "Description", ""); | ||
421 | cmd.AppendChild(e); | ||
422 | e.AppendChild(doc.CreateTextNode(c.descriptive_help)); | ||
423 | |||
424 | xml.AppendChild(cmd); | ||
425 | } | ||
426 | } | ||
427 | } | ||
428 | |||
429 | public void FromXml(XmlElement root) | ||
430 | { | ||
431 | } | ||
372 | } | 432 | } |
373 | 433 | ||
374 | public class Parser | 434 | public class Parser |
diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs index 73209be..dbf8f8c 100644 --- a/OpenSim/Framework/Console/RemoteConsole.cs +++ b/OpenSim/Framework/Console/RemoteConsole.cs | |||
@@ -26,30 +26,43 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Xml; | ||
30 | using System.Collections; | ||
29 | using System.Collections.Generic; | 31 | using System.Collections.Generic; |
30 | using System.Diagnostics; | 32 | using System.Diagnostics; |
31 | using System.Reflection; | 33 | using System.Reflection; |
32 | using System.Text; | 34 | using System.Text; |
33 | using System.Threading; | 35 | using System.Threading; |
36 | using OpenMetaverse; | ||
34 | using Nini.Config; | 37 | using Nini.Config; |
35 | using OpenSim.Framework.Servers.HttpServer; | 38 | using OpenSim.Framework.Servers.HttpServer; |
36 | using log4net; | 39 | using log4net; |
37 | 40 | ||
38 | namespace OpenSim.Framework.Console | 41 | namespace OpenSim.Framework.Console |
39 | { | 42 | { |
43 | public class ConsoleConnection | ||
44 | { | ||
45 | public int last; | ||
46 | public long lastLineSeen; | ||
47 | } | ||
48 | |||
40 | // A console that uses REST interfaces | 49 | // A console that uses REST interfaces |
41 | // | 50 | // |
42 | public class RemoteConsole : CommandConsole | 51 | public class RemoteConsole : CommandConsole |
43 | { | 52 | { |
44 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 53 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
45 | 54 | ||
46 | // private IHttpServer m_Server = null; | 55 | private IHttpServer m_Server = null; |
47 | // private IConfigSource m_Config = null; | 56 | private IConfigSource m_Config = null; |
48 | 57 | ||
49 | private List<string> m_Scrollback = new List<string>(); | 58 | private List<string> m_Scrollback = new List<string>(); |
50 | private ManualResetEvent m_DataEvent = new ManualResetEvent(false); | 59 | private ManualResetEvent m_DataEvent = new ManualResetEvent(false); |
51 | private List<string> m_InputData = new List<string>(); | 60 | private List<string> m_InputData = new List<string>(); |
52 | private uint m_LineNumber = 1; | 61 | private long m_LineNumber = 0; |
62 | private Dictionary<UUID, ConsoleConnection> m_Connections = | ||
63 | new Dictionary<UUID, ConsoleConnection>(); | ||
64 | private string m_UserName = String.Empty; | ||
65 | private string m_Password = String.Empty; | ||
53 | 66 | ||
54 | public RemoteConsole(string defaultPrompt) : base(defaultPrompt) | 67 | public RemoteConsole(string defaultPrompt) : base(defaultPrompt) |
55 | { | 68 | { |
@@ -57,12 +70,23 @@ namespace OpenSim.Framework.Console | |||
57 | 70 | ||
58 | public void ReadConfig(IConfigSource config) | 71 | public void ReadConfig(IConfigSource config) |
59 | { | 72 | { |
60 | // m_Config = config; | 73 | m_Config = config; |
74 | |||
75 | IConfig netConfig = m_Config.Configs["Network"]; | ||
76 | if (netConfig == null) | ||
77 | return; | ||
78 | |||
79 | m_UserName = netConfig.GetString("ConsoleUser", String.Empty); | ||
80 | m_Password = netConfig.GetString("ConsolePass", String.Empty); | ||
61 | } | 81 | } |
62 | 82 | ||
63 | public void SetServer(IHttpServer server) | 83 | public void SetServer(IHttpServer server) |
64 | { | 84 | { |
65 | // m_Server = server; | 85 | m_Server = server; |
86 | |||
87 | m_Server.AddHTTPHandler("/StartSession/", HandleHttpStartSession); | ||
88 | m_Server.AddHTTPHandler("/CloseSession/", HandleHttpCloseSession); | ||
89 | m_Server.AddHTTPHandler("/SessionCommand/", HandleHttpSessionCommand); | ||
66 | } | 90 | } |
67 | 91 | ||
68 | public override void Output(string text, string level) | 92 | public override void Output(string text, string level) |
@@ -71,16 +95,14 @@ namespace OpenSim.Framework.Console | |||
71 | { | 95 | { |
72 | while (m_Scrollback.Count >= 1000) | 96 | while (m_Scrollback.Count >= 1000) |
73 | m_Scrollback.RemoveAt(0); | 97 | m_Scrollback.RemoveAt(0); |
74 | m_Scrollback.Add(String.Format("{0}", m_LineNumber)+":"+level+":"+text); | ||
75 | m_LineNumber++; | 98 | m_LineNumber++; |
99 | m_Scrollback.Add(String.Format("{0}", m_LineNumber)+":"+level+":"+text); | ||
76 | } | 100 | } |
77 | System.Console.Write(text); | 101 | System.Console.Write(text); |
78 | } | 102 | } |
79 | 103 | ||
80 | public override string ReadLine(string p, bool isCommand, bool e) | 104 | public override string ReadLine(string p, bool isCommand, bool e) |
81 | { | 105 | { |
82 | System.Console.Write("{0}", prompt); | ||
83 | |||
84 | m_DataEvent.WaitOne(); | 106 | m_DataEvent.WaitOne(); |
85 | 107 | ||
86 | lock (m_InputData) | 108 | lock (m_InputData) |
@@ -115,5 +137,299 @@ namespace OpenSim.Framework.Console | |||
115 | return cmdinput; | 137 | return cmdinput; |
116 | } | 138 | } |
117 | } | 139 | } |
140 | |||
141 | private void DoExpire() | ||
142 | { | ||
143 | List<UUID> expired = new List<UUID>(); | ||
144 | |||
145 | lock (m_Connections) | ||
146 | { | ||
147 | foreach (KeyValuePair<UUID, ConsoleConnection> kvp in m_Connections) | ||
148 | { | ||
149 | if (System.Environment.TickCount - kvp.Value.last > 500000) | ||
150 | expired.Add(kvp.Key); | ||
151 | } | ||
152 | |||
153 | foreach (UUID id in expired) | ||
154 | { | ||
155 | System.Console.WriteLine("Expired {0}", id.ToString()); | ||
156 | CloseConnection(id); | ||
157 | m_Connections.Remove(id); | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | |||
162 | private Hashtable HandleHttpStartSession(Hashtable request) | ||
163 | { | ||
164 | DoExpire(); | ||
165 | |||
166 | Hashtable post = DecodePostString(request["body"].ToString()); | ||
167 | Hashtable reply = new Hashtable(); | ||
168 | |||
169 | reply["str_response_string"] = ""; | ||
170 | reply["int_response_code"] = 401; | ||
171 | reply["content_type"] = "text/plain"; | ||
172 | |||
173 | if (m_UserName == String.Empty) | ||
174 | return reply; | ||
175 | |||
176 | if (post["USER"] == null || post["PASS"] == null) | ||
177 | return reply; | ||
178 | |||
179 | if (m_UserName != post["USER"].ToString() || | ||
180 | m_Password != post["PASS"].ToString()) | ||
181 | { | ||
182 | return reply; | ||
183 | } | ||
184 | |||
185 | ConsoleConnection c = new ConsoleConnection(); | ||
186 | c.last = System.Environment.TickCount; | ||
187 | c.lastLineSeen = 0; | ||
188 | |||
189 | UUID sessionID = UUID.Random(); | ||
190 | |||
191 | lock (m_Connections) | ||
192 | { | ||
193 | m_Connections[sessionID] = c; | ||
194 | } | ||
195 | |||
196 | string uri = "/ReadResponses/" + sessionID.ToString() + "/"; | ||
197 | |||
198 | m_Server.AddPollServiceHTTPHandler(uri, HandleHttpCloseSession, | ||
199 | new PollServiceEventArgs(HasEvents, GetEvents, NoEvents, | ||
200 | sessionID)); | ||
201 | |||
202 | XmlDocument xmldoc = new XmlDocument(); | ||
203 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, | ||
204 | "", ""); | ||
205 | |||
206 | xmldoc.AppendChild(xmlnode); | ||
207 | XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", | ||
208 | ""); | ||
209 | |||
210 | xmldoc.AppendChild(rootElement); | ||
211 | |||
212 | XmlElement id = xmldoc.CreateElement("", "SessionID", ""); | ||
213 | id.AppendChild(xmldoc.CreateTextNode(sessionID.ToString())); | ||
214 | |||
215 | rootElement.AppendChild(id); | ||
216 | rootElement.AppendChild(MainConsole.Instance.Commands.GetXml(xmldoc)); | ||
217 | |||
218 | reply["str_response_string"] = xmldoc.InnerXml; | ||
219 | reply["int_response_code"] = 200; | ||
220 | reply["content_type"] = "text/xml"; | ||
221 | |||
222 | return reply; | ||
223 | } | ||
224 | |||
225 | private Hashtable HandleHttpCloseSession(Hashtable request) | ||
226 | { | ||
227 | DoExpire(); | ||
228 | |||
229 | Hashtable post = DecodePostString(request["body"].ToString()); | ||
230 | Hashtable reply = new Hashtable(); | ||
231 | |||
232 | reply["str_response_string"] = ""; | ||
233 | reply["int_response_code"] = 404; | ||
234 | reply["content_type"] = "text/plain"; | ||
235 | |||
236 | if (post["ID"] == null) | ||
237 | return reply; | ||
238 | |||
239 | UUID id; | ||
240 | if (!UUID.TryParse(post["ID"].ToString(), out id)) | ||
241 | return reply; | ||
242 | |||
243 | lock (m_Connections) | ||
244 | { | ||
245 | if (m_Connections.ContainsKey(id)) | ||
246 | { | ||
247 | CloseConnection(id); | ||
248 | m_Connections.Remove(id); | ||
249 | } | ||
250 | } | ||
251 | |||
252 | XmlDocument xmldoc = new XmlDocument(); | ||
253 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, | ||
254 | "", ""); | ||
255 | |||
256 | xmldoc.AppendChild(xmlnode); | ||
257 | XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", | ||
258 | ""); | ||
259 | |||
260 | xmldoc.AppendChild(rootElement); | ||
261 | |||
262 | XmlElement res = xmldoc.CreateElement("", "Result", ""); | ||
263 | res.AppendChild(xmldoc.CreateTextNode("OK")); | ||
264 | |||
265 | rootElement.AppendChild(res); | ||
266 | |||
267 | reply["str_response_string"] = xmldoc.InnerXml; | ||
268 | reply["int_response_code"] = 200; | ||
269 | reply["content_type"] = "text/plain"; | ||
270 | |||
271 | return reply; | ||
272 | } | ||
273 | |||
274 | private Hashtable HandleHttpSessionCommand(Hashtable request) | ||
275 | { | ||
276 | DoExpire(); | ||
277 | |||
278 | Hashtable post = DecodePostString(request["body"].ToString()); | ||
279 | Hashtable reply = new Hashtable(); | ||
280 | |||
281 | reply["str_response_string"] = ""; | ||
282 | reply["int_response_code"] = 404; | ||
283 | reply["content_type"] = "text/plain"; | ||
284 | |||
285 | if (post["ID"] == null) | ||
286 | return reply; | ||
287 | |||
288 | UUID id; | ||
289 | if (!UUID.TryParse(post["ID"].ToString(), out id)) | ||
290 | return reply; | ||
291 | |||
292 | if (post["COMMAND"] == null || post["COMMAND"].ToString() == String.Empty) | ||
293 | return reply; | ||
294 | |||
295 | lock (m_InputData) | ||
296 | { | ||
297 | m_DataEvent.Set(); | ||
298 | m_InputData.Add(post["COMMAND"].ToString()); | ||
299 | } | ||
300 | |||
301 | XmlDocument xmldoc = new XmlDocument(); | ||
302 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, | ||
303 | "", ""); | ||
304 | |||
305 | xmldoc.AppendChild(xmlnode); | ||
306 | XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", | ||
307 | ""); | ||
308 | |||
309 | xmldoc.AppendChild(rootElement); | ||
310 | |||
311 | XmlElement res = xmldoc.CreateElement("", "Result", ""); | ||
312 | res.AppendChild(xmldoc.CreateTextNode("OK")); | ||
313 | |||
314 | rootElement.AppendChild(res); | ||
315 | |||
316 | reply["str_response_string"] = xmldoc.InnerXml; | ||
317 | reply["int_response_code"] = 200; | ||
318 | reply["content_type"] = "text/plain"; | ||
319 | |||
320 | return reply; | ||
321 | } | ||
322 | |||
323 | private Hashtable DecodePostString(string data) | ||
324 | { | ||
325 | Hashtable result = new Hashtable(); | ||
326 | |||
327 | string[] terms = data.Split(new char[] {'&'}); | ||
328 | |||
329 | foreach (string term in terms) | ||
330 | { | ||
331 | string[] elems = term.Split(new char[] {'='}); | ||
332 | if (elems.Length == 0) | ||
333 | continue; | ||
334 | |||
335 | string name = System.Web.HttpUtility.UrlDecode(elems[0]); | ||
336 | string value = String.Empty; | ||
337 | |||
338 | if (elems.Length > 1) | ||
339 | value = System.Web.HttpUtility.UrlDecode(elems[1]); | ||
340 | |||
341 | result[name] = value; | ||
342 | } | ||
343 | |||
344 | return result; | ||
345 | } | ||
346 | |||
347 | public void CloseConnection(UUID id) | ||
348 | { | ||
349 | string uri = "/ReadResponses/" + id.ToString() + "/"; | ||
350 | |||
351 | m_Server.RemovePollServiceHTTPHandler("", uri); | ||
352 | } | ||
353 | |||
354 | private bool HasEvents(UUID sessionID) | ||
355 | { | ||
356 | ConsoleConnection c = null; | ||
357 | |||
358 | lock (m_Connections) | ||
359 | { | ||
360 | if (!m_Connections.ContainsKey(sessionID)) | ||
361 | return false; | ||
362 | c = m_Connections[sessionID]; | ||
363 | } | ||
364 | c.last = System.Environment.TickCount; | ||
365 | if (c.lastLineSeen < m_LineNumber) | ||
366 | return true; | ||
367 | return false; | ||
368 | } | ||
369 | |||
370 | private Hashtable GetEvents(UUID sessionID, string request) | ||
371 | { | ||
372 | ConsoleConnection c = null; | ||
373 | |||
374 | lock (m_Connections) | ||
375 | { | ||
376 | if (!m_Connections.ContainsKey(sessionID)) | ||
377 | return NoEvents(); | ||
378 | c = m_Connections[sessionID]; | ||
379 | } | ||
380 | c.last = System.Environment.TickCount; | ||
381 | if (c.lastLineSeen >= m_LineNumber) | ||
382 | return NoEvents(); | ||
383 | |||
384 | Hashtable result = new Hashtable(); | ||
385 | |||
386 | XmlDocument xmldoc = new XmlDocument(); | ||
387 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, | ||
388 | "", ""); | ||
389 | |||
390 | xmldoc.AppendChild(xmlnode); | ||
391 | XmlElement rootElement = xmldoc.CreateElement("", "ConsoleSession", | ||
392 | ""); | ||
393 | |||
394 | lock (m_Scrollback) | ||
395 | { | ||
396 | long startLine = m_LineNumber - m_Scrollback.Count; | ||
397 | |||
398 | for (long i = startLine ; i < m_LineNumber ; i++) | ||
399 | { | ||
400 | XmlElement res = xmldoc.CreateElement("", "Line", ""); | ||
401 | long line = i + 1; | ||
402 | res.SetAttribute("Number", line.ToString()); | ||
403 | res.AppendChild(xmldoc.CreateTextNode(m_Scrollback[(int)(i - startLine)])); | ||
404 | |||
405 | rootElement.AppendChild(res); | ||
406 | } | ||
407 | } | ||
408 | c.lastLineSeen = m_LineNumber; | ||
409 | |||
410 | xmldoc.AppendChild(rootElement); | ||
411 | |||
412 | result["str_response_string"] = xmldoc.InnerXml; | ||
413 | result["int_response_code"] = 200; | ||
414 | result["content_type"] = "application/xml"; | ||
415 | result["keepalive"] = false; | ||
416 | result["reusecontext"] = false; | ||
417 | |||
418 | return result; | ||
419 | } | ||
420 | |||
421 | private Hashtable NoEvents() | ||
422 | { | ||
423 | Hashtable result = new Hashtable(); | ||
424 | |||
425 | result["int_response_code"] = 502; | ||
426 | result["content_type"] = "text/plain"; | ||
427 | result["keepalive"] = false; | ||
428 | result["reusecontext"] = false; | ||
429 | result["str_response_string"] = "Upstream error: "; | ||
430 | result["error_status_text"] = "Upstream error:"; | ||
431 | |||
432 | return result; | ||
433 | } | ||
118 | } | 434 | } |
119 | } | 435 | } |
diff --git a/OpenSim/Server/Base/HttpServerBase.cs b/OpenSim/Server/Base/HttpServerBase.cs index 2142f87..791e1ef 100644 --- a/OpenSim/Server/Base/HttpServerBase.cs +++ b/OpenSim/Server/Base/HttpServerBase.cs | |||
@@ -77,16 +77,16 @@ namespace OpenSim.Server.Base | |||
77 | m_HttpServer = new BaseHttpServer(port); | 77 | m_HttpServer = new BaseHttpServer(port); |
78 | 78 | ||
79 | MainServer.Instance = m_HttpServer; | 79 | MainServer.Instance = m_HttpServer; |
80 | |||
81 | if (MainConsole.Instance is RemoteConsole) | ||
82 | { | ||
83 | ((RemoteConsole)MainConsole.Instance).SetServer(m_HttpServer); | ||
84 | } | ||
85 | } | 80 | } |
86 | 81 | ||
87 | protected override void Initialise() | 82 | protected override void Initialise() |
88 | { | 83 | { |
89 | m_HttpServer.Start(); | 84 | m_HttpServer.Start(); |
85 | |||
86 | if (MainConsole.Instance is RemoteConsole) | ||
87 | { | ||
88 | ((RemoteConsole)MainConsole.Instance).SetServer(m_HttpServer); | ||
89 | } | ||
90 | } | 90 | } |
91 | } | 91 | } |
92 | } | 92 | } |
diff --git a/prebuild.xml b/prebuild.xml index a935731..922d108 100644 --- a/prebuild.xml +++ b/prebuild.xml | |||
@@ -105,9 +105,11 @@ | |||
105 | 105 | ||
106 | <ReferencePath>../../../bin/</ReferencePath> | 106 | <ReferencePath>../../../bin/</ReferencePath> |
107 | <Reference name="System"/> | 107 | <Reference name="System"/> |
108 | <Reference name="System.Web"/> | ||
108 | <Reference name="log4net.dll"/> | 109 | <Reference name="log4net.dll"/> |
109 | <Reference name="Nini.dll"/> | 110 | <Reference name="Nini.dll"/> |
110 | <Reference name="OpenSim.Framework.Servers.HttpServer"/> | 111 | <Reference name="OpenSim.Framework.Servers.HttpServer"/> |
112 | <Reference name="OpenMetaverseTypes.dll"/> | ||
111 | <Files> | 113 | <Files> |
112 | <Match pattern="*.cs" recurse="true"/> | 114 | <Match pattern="*.cs" recurse="true"/> |
113 | </Files> | 115 | </Files> |