diff options
author | lbsa71 | 2008-06-24 21:09:49 +0000 |
---|---|---|
committer | lbsa71 | 2008-06-24 21:09:49 +0000 |
commit | 6b7930104bdb845d3b9c085dc04f52b6446f23b1 (patch) | |
tree | 05ee45781a455817fa400bb99f30f4d19d4eb1f8 /OpenSim/Region/ScriptEngine/XEngine/Compiler.cs | |
parent | based on positive feedback on performance of making keys fixed length (diff) | |
download | opensim-SC-6b7930104bdb845d3b9c085dc04f52b6446f23b1.zip opensim-SC-6b7930104bdb845d3b9c085dc04f52b6446f23b1.tar.gz opensim-SC-6b7930104bdb845d3b9c085dc04f52b6446f23b1.tar.bz2 opensim-SC-6b7930104bdb845d3b9c085dc04f52b6446f23b1.tar.xz |
* Applied patch from Melanie, mantis issue #1581 - "Refactor LSL language, api and compiler out of XEngine"
"First stage in a major Script Engine refactor, that will result in the LSL implementaions ebing reconverged. Not there yet, but one major part is done."
Thank you, Melanie!
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs (renamed from OpenSim/Region/ScriptEngine/XEngine/Compiler.cs) | 70 |
1 files changed, 35 insertions, 35 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/Compiler.cs b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs index 68fb1dd..2edcee0 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/Compiler.cs +++ b/OpenSim/Region/ScriptEngine/Shared/CodeTools/Compiler.cs | |||
@@ -34,8 +34,9 @@ using Microsoft.CSharp; | |||
34 | using Microsoft.JScript; | 34 | using Microsoft.JScript; |
35 | using Microsoft.VisualBasic; | 35 | using Microsoft.VisualBasic; |
36 | using OpenSim.Region.Environment.Interfaces; | 36 | using OpenSim.Region.Environment.Interfaces; |
37 | using OpenSim.Region.ScriptEngine.Interfaces; | ||
37 | 38 | ||
38 | namespace OpenSim.Region.ScriptEngine.XEngine | 39 | namespace OpenSim.Region.ScriptEngine.Shared.CodeTools |
39 | { | 40 | { |
40 | public class Compiler | 41 | public class Compiler |
41 | { | 42 | { |
@@ -78,8 +79,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
78 | private static int instanceID = new Random().Next(0, int.MaxValue); // Unique number to use on our compiled files | 79 | private static int instanceID = new Random().Next(0, int.MaxValue); // Unique number to use on our compiled files |
79 | private static UInt64 scriptCompileCounter = 0; // And a counter | 80 | private static UInt64 scriptCompileCounter = 0; // And a counter |
80 | 81 | ||
81 | public XEngine m_scriptEngine; | 82 | public IScriptEngine m_scriptEngine; |
82 | public Compiler(XEngine scriptEngine) | 83 | public Compiler(IScriptEngine scriptEngine) |
83 | { | 84 | { |
84 | m_scriptEngine = scriptEngine; | 85 | m_scriptEngine = scriptEngine; |
85 | ReadConfig(); | 86 | ReadConfig(); |
@@ -89,11 +90,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
89 | { | 90 | { |
90 | 91 | ||
91 | // Get some config | 92 | // Get some config |
92 | WriteScriptSourceToDebugFile = m_scriptEngine.ScriptConfigSource.GetBoolean("WriteScriptSourceToDebugFile", true); | 93 | WriteScriptSourceToDebugFile = m_scriptEngine.Config.GetBoolean("WriteScriptSourceToDebugFile", true); |
93 | CompileWithDebugInformation = m_scriptEngine.ScriptConfigSource.GetBoolean("CompileWithDebugInformation", true); | 94 | CompileWithDebugInformation = m_scriptEngine.Config.GetBoolean("CompileWithDebugInformation", true); |
94 | 95 | ||
95 | // Get file prefix from scriptengine name and make it file system safe: | 96 | // Get file prefix from scriptengine name and make it file system safe: |
96 | FilePrefix = m_scriptEngine.ScriptEngineName; | 97 | FilePrefix = "CommonCompiler"; |
97 | foreach (char c in Path.GetInvalidFileNameChars()) | 98 | foreach (char c in Path.GetInvalidFileNameChars()) |
98 | { | 99 | { |
99 | FilePrefix = FilePrefix.Replace(c, '_'); | 100 | FilePrefix = FilePrefix.Replace(c, '_'); |
@@ -113,11 +114,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
113 | LanguageMapping.Add(enumCompileType.js.ToString(), enumCompileType.js); | 114 | LanguageMapping.Add(enumCompileType.js.ToString(), enumCompileType.js); |
114 | 115 | ||
115 | // Allowed compilers | 116 | // Allowed compilers |
116 | string allowComp = m_scriptEngine.ScriptConfigSource.GetString("AllowedCompilers", "lsl,cs,vb,js"); | 117 | string allowComp = m_scriptEngine.Config.GetString("AllowedCompilers", "lsl,cs,vb,js"); |
117 | AllowedCompilers.Clear(); | 118 | AllowedCompilers.Clear(); |
118 | 119 | ||
119 | #if DEBUG | 120 | #if DEBUG |
120 | m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Allowed languages: " + allowComp); | 121 | m_scriptEngine.Log.Debug("[Compiler]: Allowed languages: " + allowComp); |
121 | #endif | 122 | #endif |
122 | 123 | ||
123 | 124 | ||
@@ -126,26 +127,26 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
126 | string strlan = strl.Trim(" \t".ToCharArray()).ToLower(); | 127 | string strlan = strl.Trim(" \t".ToCharArray()).ToLower(); |
127 | if (!LanguageMapping.ContainsKey(strlan)) | 128 | if (!LanguageMapping.ContainsKey(strlan)) |
128 | { | 129 | { |
129 | m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Config error. Compiler is unable to recognize language type \"" + strlan + "\" specified in \"AllowedCompilers\"."); | 130 | m_scriptEngine.Log.Error("[Compiler]: Config error. Compiler is unable to recognize language type \"" + strlan + "\" specified in \"AllowedCompilers\"."); |
130 | } | 131 | } |
131 | else | 132 | else |
132 | { | 133 | { |
133 | #if DEBUG | 134 | #if DEBUG |
134 | //m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Config OK. Compiler recognized language type \"" + strlan + "\" specified in \"AllowedCompilers\"."); | 135 | //m_scriptEngine.Log.Debug("[Compiler]: Config OK. Compiler recognized language type \"" + strlan + "\" specified in \"AllowedCompilers\"."); |
135 | #endif | 136 | #endif |
136 | } | 137 | } |
137 | AllowedCompilers.Add(strlan, true); | 138 | AllowedCompilers.Add(strlan, true); |
138 | } | 139 | } |
139 | if (AllowedCompilers.Count == 0) | 140 | if (AllowedCompilers.Count == 0) |
140 | m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Config error. Compiler could not recognize any language in \"AllowedCompilers\". Scripts will not be executed!"); | 141 | m_scriptEngine.Log.Error("[Compiler]: Config error. Compiler could not recognize any language in \"AllowedCompilers\". Scripts will not be executed!"); |
141 | 142 | ||
142 | // Default language | 143 | // Default language |
143 | string defaultCompileLanguage = m_scriptEngine.ScriptConfigSource.GetString("DefaultCompileLanguage", "lsl").ToLower(); | 144 | string defaultCompileLanguage = m_scriptEngine.Config.GetString("DefaultCompileLanguage", "lsl").ToLower(); |
144 | 145 | ||
145 | // Is this language recognized at all? | 146 | // Is this language recognized at all? |
146 | if (!LanguageMapping.ContainsKey(defaultCompileLanguage)) | 147 | if (!LanguageMapping.ContainsKey(defaultCompileLanguage)) |
147 | { | 148 | { |
148 | m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: " + | 149 | m_scriptEngine.Log.Error("[Compiler]: " + |
149 | "Config error. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is not recognized as a valid language. Changing default to: \"lsl\"."); | 150 | "Config error. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is not recognized as a valid language. Changing default to: \"lsl\"."); |
150 | defaultCompileLanguage = "lsl"; | 151 | defaultCompileLanguage = "lsl"; |
151 | } | 152 | } |
@@ -153,13 +154,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
153 | // Is this language in allow-list? | 154 | // Is this language in allow-list? |
154 | if (!AllowedCompilers.ContainsKey(defaultCompileLanguage)) | 155 | if (!AllowedCompilers.ContainsKey(defaultCompileLanguage)) |
155 | { | 156 | { |
156 | m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: " + | 157 | m_scriptEngine.Log.Error("[Compiler]: " + |
157 | "Config error. Default language \"" + defaultCompileLanguage + "\"specified in \"DefaultCompileLanguage\" is not in list of \"AllowedCompilers\". Scripts may not be executed!"); | 158 | "Config error. Default language \"" + defaultCompileLanguage + "\"specified in \"DefaultCompileLanguage\" is not in list of \"AllowedCompilers\". Scripts may not be executed!"); |
158 | } | 159 | } |
159 | else | 160 | else |
160 | { | 161 | { |
161 | #if DEBUG | 162 | #if DEBUG |
162 | // m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: " + | 163 | // m_scriptEngine.Log.Debug("[Compiler]: " + |
163 | // "Config OK. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is recognized as a valid language."); | 164 | // "Config OK. Default language \"" + defaultCompileLanguage + "\" specified in \"DefaultCompileLanguage\" is recognized as a valid language."); |
164 | #endif | 165 | #endif |
165 | // LANGUAGE IS IN ALLOW-LIST | 166 | // LANGUAGE IS IN ALLOW-LIST |
@@ -185,7 +186,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
185 | } | 186 | } |
186 | catch (Exception ex) | 187 | catch (Exception ex) |
187 | { | 188 | { |
188 | m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception trying to create ScriptEngine directory \"" + ScriptEnginesPath + "\": " + ex.ToString()); | 189 | m_scriptEngine.Log.Error("[Compiler]: Exception trying to create ScriptEngine directory \"" + ScriptEnginesPath + "\": " + ex.ToString()); |
189 | } | 190 | } |
190 | } | 191 | } |
191 | 192 | ||
@@ -199,7 +200,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
199 | } | 200 | } |
200 | catch (Exception ex) | 201 | catch (Exception ex) |
201 | { | 202 | { |
202 | m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception trying to create ScriptEngine directory \"" + Path.Combine(ScriptEnginesPath, | 203 | m_scriptEngine.Log.Error("[Compiler]: Exception trying to create ScriptEngine directory \"" + Path.Combine(ScriptEnginesPath, |
203 | m_scriptEngine.World.RegionInfo.RegionID.ToString())+ "\": " + ex.ToString()); | 204 | m_scriptEngine.World.RegionInfo.RegionID.ToString())+ "\": " + ex.ToString()); |
204 | } | 205 | } |
205 | } | 206 | } |
@@ -207,7 +208,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
207 | foreach (string file in Directory.GetFiles(Path.Combine(ScriptEnginesPath, | 208 | foreach (string file in Directory.GetFiles(Path.Combine(ScriptEnginesPath, |
208 | m_scriptEngine.World.RegionInfo.RegionID.ToString()))) | 209 | m_scriptEngine.World.RegionInfo.RegionID.ToString()))) |
209 | { | 210 | { |
210 | //m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: FILE FOUND: " + file); | 211 | //m_scriptEngine.Log.Error("[Compiler]: FILE FOUND: " + file); |
211 | 212 | ||
212 | if (file.ToLower().StartsWith(FilePrefix + "_compiled_") || | 213 | if (file.ToLower().StartsWith(FilePrefix + "_compiled_") || |
213 | file.ToLower().StartsWith(FilePrefix + "_source_")) | 214 | file.ToLower().StartsWith(FilePrefix + "_source_")) |
@@ -218,7 +219,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
218 | } | 219 | } |
219 | catch (Exception ex) | 220 | catch (Exception ex) |
220 | { | 221 | { |
221 | m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception trying delete old script file \"" + file + "\": " + ex.ToString()); | 222 | m_scriptEngine.Log.Error("[Compiler]: Exception trying delete old script file \"" + file + "\": " + ex.ToString()); |
222 | } | 223 | } |
223 | 224 | ||
224 | } | 225 | } |
@@ -233,10 +234,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
233 | // { | 234 | // { |
234 | // case ".txt": | 235 | // case ".txt": |
235 | // case ".lsl": | 236 | // case ".lsl": |
236 | // Common.ScriptEngineBase.Common.SendToDebug("Source code is LSL, converting to CS"); | 237 | // Common.ScriptEngineBase.Shared.SendToDebug("Source code is LSL, converting to CS"); |
237 | // return CompileFromLSLText(File.ReadAllText(LSOFileName)); | 238 | // return CompileFromLSLText(File.ReadAllText(LSOFileName)); |
238 | // case ".cs": | 239 | // case ".cs": |
239 | // Common.ScriptEngineBase.Common.SendToDebug("Source code is CS"); | 240 | // Common.ScriptEngineBase.Shared.SendToDebug("Source code is CS"); |
240 | // return CompileFromCSText(File.ReadAllText(LSOFileName)); | 241 | // return CompileFromCSText(File.ReadAllText(LSOFileName)); |
241 | // default: | 242 | // default: |
242 | // throw new Exception("Unknown script type."); | 243 | // throw new Exception("Unknown script type."); |
@@ -258,7 +259,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
258 | 259 | ||
259 | if (File.Exists(OutFile)) | 260 | if (File.Exists(OutFile)) |
260 | { | 261 | { |
261 | m_scriptEngine.Log.DebugFormat("[XEngine] Returning existing assembly for {0}", asset); | 262 | m_scriptEngine.Log.DebugFormat("[Compiler] Returning existing assembly for {0}", asset); |
262 | return OutFile; | 263 | return OutFile; |
263 | } | 264 | } |
264 | 265 | ||
@@ -359,9 +360,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
359 | private static string CreateJSCompilerScript(string compileScript) | 360 | private static string CreateJSCompilerScript(string compileScript) |
360 | { | 361 | { |
361 | compileScript = String.Empty + | 362 | compileScript = String.Empty + |
362 | "import OpenSim.Region.ScriptEngine.XEngine.Script; import System.Collections.Generic;\r\n" + | 363 | "import OpenSim.Region.ScriptEngine.Shared; import System.Collections.Generic;\r\n" + |
363 | "package SecondLife {\r\n" + | 364 | "package SecondLife {\r\n" + |
364 | "class Script extends OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass { \r\n" + | 365 | "class Script extends OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + |
365 | compileScript + | 366 | compileScript + |
366 | "} }\r\n"; | 367 | "} }\r\n"; |
367 | return compileScript; | 368 | return compileScript; |
@@ -370,9 +371,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
370 | private static string CreateCSCompilerScript(string compileScript) | 371 | private static string CreateCSCompilerScript(string compileScript) |
371 | { | 372 | { |
372 | compileScript = String.Empty + | 373 | compileScript = String.Empty + |
373 | "using OpenSim.Region.ScriptEngine.XEngine.Script; using System.Collections.Generic;\r\n" + | 374 | "using OpenSim.Region.ScriptEngine.Shared; using System.Collections.Generic;\r\n" + |
374 | String.Empty + "namespace SecondLife { " + | 375 | String.Empty + "namespace SecondLife { " + |
375 | String.Empty + "public class Script : OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass { \r\n" + | 376 | String.Empty + "public class Script : OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass { \r\n" + |
376 | @"public Script() { } " + | 377 | @"public Script() { } " + |
377 | compileScript + | 378 | compileScript + |
378 | "} }\r\n"; | 379 | "} }\r\n"; |
@@ -382,9 +383,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
382 | private static string CreateVBCompilerScript(string compileScript) | 383 | private static string CreateVBCompilerScript(string compileScript) |
383 | { | 384 | { |
384 | compileScript = String.Empty + | 385 | compileScript = String.Empty + |
385 | "Imports OpenSim.Region.ScriptEngine.XEngine.Script: Imports System.Collections.Generic: " + | 386 | "Imports OpenSim.Region.ScriptEngine.Shared: Imports System.Collections.Generic: " + |
386 | String.Empty + "NameSpace SecondLife:" + | 387 | String.Empty + "NameSpace SecondLife:" + |
387 | String.Empty + "Public Class Script: Inherits OpenSim.Region.ScriptEngine.XEngine.Script.BuiltIn_Commands_BaseClass: " + | 388 | String.Empty + "Public Class Script: Inherits OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass: " + |
388 | "\r\nPublic Sub New()\r\nEnd Sub: " + | 389 | "\r\nPublic Sub New()\r\nEnd Sub: " + |
389 | compileScript + | 390 | compileScript + |
390 | ":End Class :End Namespace\r\n"; | 391 | ":End Class :End Namespace\r\n"; |
@@ -406,7 +407,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
406 | m_scriptEngine.World.RegionInfo.RegionID.ToString(), | 407 | m_scriptEngine.World.RegionInfo.RegionID.ToString(), |
407 | FilePrefix + "_compiled_" + asset + ".dll")); | 408 | FilePrefix + "_compiled_" + asset + ".dll")); |
408 | #if DEBUG | 409 | #if DEBUG |
409 | // m_scriptEngine.Log.Debug("[" + m_scriptEngine.ScriptEngineName + "]: Starting compile of \"" + OutFile + "\"."); | 410 | // m_scriptEngine.Log.Debug("[Compiler]: Starting compile of \"" + OutFile + "\"."); |
410 | #endif | 411 | #endif |
411 | try | 412 | try |
412 | { | 413 | { |
@@ -414,7 +415,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
414 | } | 415 | } |
415 | catch (Exception e) // NOTLEGIT - Should be just catching FileIOException | 416 | catch (Exception e) // NOTLEGIT - Should be just catching FileIOException |
416 | { | 417 | { |
417 | //m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString()); | 418 | //m_scriptEngine.Log.Error("[Compiler]: Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString()); |
418 | throw new Exception("Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString()); | 419 | throw new Exception("Unable to delete old existring script-file before writing new. Compile aborted: " + e.ToString()); |
419 | } | 420 | } |
420 | //string OutFile = Path.Combine("ScriptEngines", "SecondLife.Script.dll"); | 421 | //string OutFile = Path.Combine("ScriptEngines", "SecondLife.Script.dll"); |
@@ -432,7 +433,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
432 | } | 433 | } |
433 | catch (Exception ex) // NOTLEGIT - Should be just catching FileIOException | 434 | catch (Exception ex) // NOTLEGIT - Should be just catching FileIOException |
434 | { | 435 | { |
435 | m_scriptEngine.Log.Error("[" + m_scriptEngine.ScriptEngineName + "]: Exception while trying to write script source to file \"" + srcFileName + "\": " + ex.ToString()); | 436 | m_scriptEngine.Log.Error("[Compiler]: Exception while trying to write script source to file \"" + srcFileName + "\": " + ex.ToString()); |
436 | } | 437 | } |
437 | } | 438 | } |
438 | 439 | ||
@@ -451,10 +452,9 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
451 | string rootPath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); | 452 | string rootPath = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory); |
452 | string rootPathSE = Path.GetDirectoryName(GetType().Assembly.Location); | 453 | string rootPathSE = Path.GetDirectoryName(GetType().Assembly.Location); |
453 | //Console.WriteLine("Assembly location: " + rootPath); | 454 | //Console.WriteLine("Assembly location: " + rootPath); |
454 | parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.XEngine.Script.dll")); | 455 | parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.dll")); |
455 | // parameters.ReferencedAssemblies.Add(Path.Combine(rootPathSE, "OpenSim.Region.ScriptEngine.XEngine.dll")); | 456 | parameters.ReferencedAssemblies.Add(Path.Combine(rootPath, "OpenSim.Region.ScriptEngine.Shared.Api.Runtime.dll")); |
456 | 457 | ||
457 | //parameters.ReferencedAssemblies.Add("OpenSim.Region.Environment"); | ||
458 | parameters.GenerateExecutable = false; | 458 | parameters.GenerateExecutable = false; |
459 | parameters.OutputAssembly = OutFile; | 459 | parameters.OutputAssembly = OutFile; |
460 | parameters.IncludeDebugInformation = CompileWithDebugInformation; | 460 | parameters.IncludeDebugInformation = CompileWithDebugInformation; |
@@ -508,7 +508,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine | |||
508 | errtext += "No compile error. But not able to locate compiled file."; | 508 | errtext += "No compile error. But not able to locate compiled file."; |
509 | throw new Exception(errtext); | 509 | throw new Exception(errtext); |
510 | } | 510 | } |
511 | m_scriptEngine.Log.DebugFormat("[XEngine] Compiled new assembly for {0}", asset); | 511 | m_scriptEngine.Log.DebugFormat("[Compiler] Compiled new assembly for {0}", asset); |
512 | return OutFile; | 512 | return OutFile; |
513 | } | 513 | } |
514 | } | 514 | } |