Просмотр исходного кода

1. 移除多余脚本代码
2. 优化OPCUA

Shun 2 лет назад
Родитель
Сommit
90084aad70

+ 1 - 3
src/YSAI.DAQ/YSAI.Core/YSAI.Core.csproj

@@ -5,16 +5,14 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
     <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-    <Version>1.0.0.57</Version>
+    <Version>1.0.0.58</Version>
     <Authors>Shun</Authors>
     <Company>YSAI</Company>
     <Product>SCADA</Product>
     <GenerateDocumentationFile>True</GenerateDocumentationFile>
-	<SatelliteResourceLanguages>zh-Hans</SatelliteResourceLanguages>
   </PropertyGroup>
 
 	<ItemGroup>
-		<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.7.0" />
 		<PackageReference Include="StackExchange.Redis" Version="2.6.122" />
 		<PackageReference Include="Microsoft.ClearScript" Version="7.4.4" />
 		<PackageReference Include="System.IO.Ports" Version="7.0.0" />

+ 0 - 15
src/YSAI.DAQ/YSAI.Core/handler/RuleHandler.cs

@@ -1,15 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace YSAI.Core.handler
-{
-    /// <summary>
-    /// 规则处理
-    /// </summary>
-    public class RuleHandler
-    {
-    }
-}

+ 1 - 2
src/YSAI.DAQ/YSAI.Core/script/ScriptData.cs

@@ -34,8 +34,7 @@ namespace YSAI.Core.script
         /// </summary>
         public enum ScriptType
         {
-            JavaScript,
-            CSharp
+            JavaScript
         }
 
     }

+ 0 - 3
src/YSAI.DAQ/YSAI.Core/script/ScriptOperate.cs

@@ -113,9 +113,6 @@ namespace YSAI.Core.script
                             engine.Execute(ScriptCode);  //执行脚本
                             RetParam = engine.Invoke(ScriptFunction, ScriptParam).ToString();
                         }
-                        break;
-                    case ScriptData.ScriptType.CSharp:
-
                         break;
                 }
                 return Break("Execute", true, RData: RetParam, RType: @enum.ResultType.String);

+ 40 - 28
src/YSAI.DAQ/YSAI.Opc/Opc.Ua.Client.Config.xml

@@ -48,41 +48,53 @@
   <TransportConfigurations></TransportConfigurations>
   
   <TransportQuotas>
-    <OperationTimeout>6000000</OperationTimeout>
-    <MaxStringLength>1048576</MaxStringLength>
-    <MaxByteStringLength>1048576</MaxByteStringLength>
-    <MaxArrayLength>65535</MaxArrayLength>
-    <MaxMessageSize>419430400</MaxMessageSize>
-    <MaxBufferSize>65535</MaxBufferSize>
-    <ChannelLifetime>-1</ChannelLifetime>
-    <SecurityTokenLifetime>-1</SecurityTokenLifetime>
+	  <OperationTimeout>600000</OperationTimeout>
+	  <MaxStringLength>1048576</MaxStringLength>
+	  <MaxByteStringLength>4194304</MaxByteStringLength>
+	  <MaxArrayLength>65535</MaxArrayLength>
+	  <MaxMessageSize>4194304</MaxMessageSize>
+	  <MaxBufferSize>65535</MaxBufferSize>
+	  <ChannelLifetime>300000</ChannelLifetime>
+	  <SecurityTokenLifetime>3600000</SecurityTokenLifetime>
   </TransportQuotas>
 
-  <ClientConfiguration>
-    <DefaultSessionTimeout>-1</DefaultSessionTimeout>
-    <MinSubscriptionLifetime>-1</MinSubscriptionLifetime>
-  </ClientConfiguration>
+	<!-- This element is only required for Client and ClientServer applications -->
+	<ClientConfiguration>
 
-  <DisableHiResClock>true</DisableHiResClock>
+		<!-- The default timeout for new sessions -->
+		<DefaultSessionTimeout>60000</DefaultSessionTimeout>
+
+		<!-- The well-known URLs for the local discovery servers
+             URLs are tested in the order they appear in this list. -->
+		<WellKnownDiscoveryUrls></WellKnownDiscoveryUrls>
+
+		<!-- EndpointDescriptions for system wide discovery servers -->
+		<DiscoveryServers></DiscoveryServers>
 
-  <Extensions>
-  </Extensions>
+		<!-- The minimum subscription lifetime.
+          This ensures subscriptions are not set to expire too quickly. The requesed lifetime count
+          and keep alive count are calculated using this value and the request publishing interval -->
+		<MinSubscriptionLifetime>10000</MinSubscriptionLifetime>
+	</ClientConfiguration>
 
   <TraceConfiguration>
     <OutputFilePath>%LocalApplicationData%/log/Opc.Ua.Client.log.txt</OutputFilePath>
-    <DeleteOnLoad>true</DeleteOnLoad>
-    <!-- Show Only Errors -->
-    <!-- <TraceMasks>1</TraceMasks> -->
-    <!-- Show Only Security and Errors -->
-    <!-- <TraceMasks>513</TraceMasks> -->
-    <!-- Show Only Security, Errors and Trace -->
-    <!-- <TraceMasks>515</TraceMasks> -->
-    <!-- Show Only Security, COM Calls, Errors and Trace -->
-    <!-- <TraceMasks>771</TraceMasks> -->
-    <!-- Show Only Security, Service Calls, Errors and Trace -->
-    <!-- <TraceMasks>523</TraceMasks> -->
-    <!-- Show Only Security, ServiceResultExceptions, Errors and Trace -->
-    <!-- <TraceMasks>519</TraceMasks> -->
+	  <DeleteOnLoad>true</DeleteOnLoad>
+	  <!-- Show Only Errors -->
+	  <!-- <TraceMasks>1</TraceMasks> -->
+	  <!-- Show Only Security and Errors -->
+	  <!-- <TraceMasks>513</TraceMasks> -->
+	  <!-- Show Only Security, Errors and Trace -->
+	  <!-- <TraceMasks>515</TraceMasks> -->
+	  <!-- Show Only Security, COM Calls, Errors and Trace -->
+	  <!-- <TraceMasks>771</TraceMasks> -->
+	  <!-- Show Only Security, Service Calls, Errors and Trace -->
+	  <!-- <TraceMasks>523</TraceMasks> -->
+	  <!-- Show Only Security, ServiceResultExceptions, Errors and Trace -->
+	  <TraceMasks>519</TraceMasks>
   </TraceConfiguration>
+
+  <!-- Disables the hi-res clock if the QueryPerformanceCounter does work on a particular machine. -->
+  <DisableHiResClock>true</DisableHiResClock>
   
 </ApplicationConfiguration>

+ 0 - 1
src/YSAI.DAQ/YSAI.Opc/da/client/OpcDaClientOperate.cs

@@ -696,7 +696,6 @@ namespace YSAI.Opc.da.client
                                 //判断连接状态
                                 if (opcDaClient.IsConnected)
                                 {
-
                                     //当队列为空,初始化队列
                                     if (DataQueue == null)
                                     {

+ 6 - 6
src/YSAI.DAQ/YSAI.Opc/da/http/OpcDaHttpOperate.cs

@@ -184,11 +184,11 @@ namespace YSAI.Opc.da.http
         /// </param>
         /// <param name="Param">参数</param>
         /// <returns>统一出参</returns>
-        public OperateResult Request(int requestApi, object? Param = null)
+        public OperateResult Request(OpcDaHttpData.RequestMethod requestApi, object? Param = null)
         {
             //开始记录运行时间
             Depart("Request");
-            OpcDaHttpData.RequestMethod request = (OpcDaHttpData.RequestMethod)requestApi;
+            OpcDaHttpData.RequestMethod request = requestApi;
             try
             {
                 //json 字符串
@@ -290,7 +290,7 @@ namespace YSAI.Opc.da.http
         /// </param>
         /// <param name="Param">参数</param>
         /// <returns>统一出参</returns>
-        public Task<OperateResult> RequestAsync(int requestApi, object? Param = null)
+        public Task<OperateResult> RequestAsync(OpcDaHttpData.RequestMethod requestApi, object? Param = null)
         {
             return Task.Run(() => Request(requestApi, Param));
         }
@@ -335,14 +335,14 @@ namespace YSAI.Opc.da.http
                                 read = JsonTool.StringToJsonEntity<OpcDaHttpData.ExtendParam.Read>(addressDetails.AddressExtendParam.ToString());
                             }
                             //先去判断当前连接的状态
-                            OperateResult param = Request((int)OpcDaHttpData.RequestMethod.ReqGetConnectStatusOfOPC, new ReqGetConnectStatusOfOPC.Request() { opcname = read.ServerName });
+                            OperateResult param = Request(OpcDaHttpData.RequestMethod.ReqGetConnectStatusOfOPC, new ReqGetConnectStatusOfOPC.Request() { opcname = read.ServerName });
                             if (!param.State)
                             {
                                 //状态失败的话,就连接此服务名
-                                Request((int)OpcDaHttpData.RequestMethod.ReqConnectToOPC, new ReqConnectToOPC.Request() { opcname = read.ServerName });
+                                Request(OpcDaHttpData.RequestMethod.ReqConnectToOPC, new ReqConnectToOPC.Request() { opcname = read.ServerName });
                             }
                             //在进行获取组下所有标签数据
-                            param = Request((int)OpcDaHttpData.RequestMethod.ReqReadItemsValueOfGroup, new ReqReadItemsValueOfGroup.Request() { opcname = read.ServerName, groupname = read.GroupName });
+                            param = Request(OpcDaHttpData.RequestMethod.ReqReadItemsValueOfGroup, new ReqReadItemsValueOfGroup.Request() { opcname = read.ServerName, groupname = read.GroupName });
                             if (param.State)
                             {
                                 ReqReadItemsValueOfGroup.Response response = param.RData as ReqReadItemsValueOfGroup.Response;

+ 1 - 1
src/YSAI.DAQ/YSAI.Opc/ua/client/OpcUaClientData.cs

@@ -52,7 +52,7 @@ namespace YSAI.Opc.ua.client
             /// 自定义名称(唯一)
             /// </summary>
             [Description("自定义名称(唯一)")]
-            public string? CustomName { get; set; } = Guid.NewGuid().ToString().Replace("-", string.Empty).Trim().ToUpper();
+            public string? CustomName { get; set; } = Guid.NewGuid().ToNString().ToUpper();
 
             /// <summary>
             /// 超时时间

+ 15 - 9
src/YSAI.DAQ/YSAI.Opc/ua/client/OpcUaClientOperate.cs

@@ -1217,6 +1217,7 @@ namespace YSAI.Opc.ua.client
                         throw new Exception(string.Format("证书验证错误:{0},{1}", eventArgs.Error.Code, eventArgs.Error.AdditionalInfo));
                     }
                 };
+              
                 //用配置的当前状态更新验证器。
                 certificateValidator.Update(new SecurityConfiguration
                 {
@@ -1265,13 +1266,6 @@ namespace YSAI.Opc.ua.client
                     MaxPublishRequestCount = int.MaxValue
                 };
 
-                //查找与当前设置最匹配的端点
-                EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(basics.ServerUrl, false);
-                //使用合理的默认值创建配置的实例
-                EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(AC);
-                //配置终端
-                ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
-
                 //证书跟密钥的设置,首选证书设置,如两个都为空则是匿名访问
                 if (!basics.Cer.IsEmpty() && !basics.SecreKey.IsEmpty())//设置证书
                 {
@@ -1282,8 +1276,21 @@ namespace YSAI.Opc.ua.client
                 {
                     UserIdentity = new UserIdentity(basics.UserName, basics.Password);
                 }
+
+                //查找与当前设置最匹配的端点
+                EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint(basics.ServerUrl, false);
+
+                //使用合理的默认值创建配置的实例
+                EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(AC);
+
+                //配置终端
+                ConfiguredEndpoint endpoint = new ConfiguredEndpoint(endpointDescription.Server, endpointConfiguration);
+
+                //更新端点描述
+                endpoint.Update(endpointDescription);
+
                 //通过调用CreateSession服务创建与服务器的新通信会话
-                clientSession = Session.Create(AC, endpoint, false, false, AC.ApplicationName, (uint)basics.Timeout, UserIdentity, null).WaitAsync(new TimeSpan(0, 0, 0, 0, basics.Timeout)).Result;
+                clientSession = Session.Create(AC, endpoint, true, false,$"{AC.ApplicationName}.{Guid.NewGuid().ToNString()}", (uint)basics.Timeout, UserIdentity, new string[] { }).WaitAsync(new TimeSpan(0, 0, 0, 0, basics.Timeout)).Result;
 
                 //当会话关闭,则关闭订阅
                 clientSession.DeleteSubscriptionsOnClose = true;
@@ -1291,7 +1298,6 @@ namespace YSAI.Opc.ua.client
                 //当从服务器到达一个存活状态或检测到一个错误时将被引发
                 clientSession.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);
 
-
                 //当队列为空,初始化队列
                 if (DataQueue == null)
                 {

+ 1 - 1
src/YSAI.DAQ/YSAI.Test.Console/Program.cs

@@ -1,4 +1,4 @@
-
+Console.WriteLine(  );
 
 //using YSAI.Opc.ua.client;
 

+ 17 - 17
src/YSAI.DAQ/YSAI.Tool.Core/opc/da/http/OpcDaHttpClientToolController.cs

@@ -288,7 +288,7 @@ namespace YSAI.Tool.Core.opc.da.http
                     return;
                 }
                 //先请求服务名下的所有节点数据
-                reverseBackParam = Operate.Request((int)RequestMethod.ReqGetALLItemsOfOPC, new ReqGetALLItemsOfOPC.Request() { opcname = ServerName });
+                reverseBackParam = Operate.Request(RequestMethod.ReqGetALLItemsOfOPC, new ReqGetALLItemsOfOPC.Request() { opcname = ServerName });
                 MessageOut(reverseBackParam.Message);
                 if (reverseBackParam.State)
                 {
@@ -305,7 +305,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         }
                         if (itemlists.Count > 0)
                         {
-                            reverseBackParam = Operate.Request((int)RequestMethod.ReqAddItemsOfGroup, new ReqAddItemsOfGroup.Request() { opcname = ServerName, groupname = GroupName, itemlist = itemlists });
+                            reverseBackParam = Operate.Request(RequestMethod.ReqAddItemsOfGroup, new ReqAddItemsOfGroup.Request() { opcname = ServerName, groupname = GroupName, itemlist = itemlists });
                             MessageOut(reverseBackParam.Message);
                         }
                         else
@@ -332,7 +332,7 @@ namespace YSAI.Tool.Core.opc.da.http
             switch (requestMethod)
             {
                 case RequestMethod.ReqOPCServerNameList:
-                    reverseBackParam = Operate.Request((int)requestMethod);
+                    reverseBackParam = Operate.Request(requestMethod);
                     if (reverseBackParam.State)
                     {
                         ReqOPCServerNameList.Response response = reverseBackParam.RData as ReqOPCServerNameList.Response;
@@ -349,7 +349,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqConnectToOPC.Request() { opcname = ServerName });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqConnectToOPC.Request() { opcname = ServerName });
                     break;
                 case RequestMethod.ReqGetALLItemsOfOPC:
                     if (string.IsNullOrEmpty(ServerName))
@@ -358,7 +358,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqGetALLItemsOfOPC.Request() { opcname = ServerName });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqGetALLItemsOfOPC.Request() { opcname = ServerName });
                     break;
                 case RequestMethod.ReqReConnectOfOPC:
                     if (string.IsNullOrEmpty(ServerName))
@@ -367,7 +367,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqReConnectOfOPC.Request() { opcname = ServerName });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqReConnectOfOPC.Request() { opcname = ServerName });
                     break;
                 case RequestMethod.ReqDisConnectOfOPC:
                     if (string.IsNullOrEmpty(ServerName))
@@ -376,7 +376,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqDisConnectOfOPC.Request() { opcname = ServerName });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqDisConnectOfOPC.Request() { opcname = ServerName });
                     break;
                 case RequestMethod.ReqDeleteConnectOfOPC:
                     if (string.IsNullOrEmpty(ServerName))
@@ -385,7 +385,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqDeleteConnectOfOPC.Request() { opcname = ServerName });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqDeleteConnectOfOPC.Request() { opcname = ServerName });
                     break;
                 case RequestMethod.ReqAddGroupOfOPC:
                     if (string.IsNullOrEmpty(ServerName) || string.IsNullOrEmpty(GroupName))
@@ -394,7 +394,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqAddGroupOfOPC.Request() { opcname = ServerName, groupname = GroupName });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqAddGroupOfOPC.Request() { opcname = ServerName, groupname = GroupName });
                     break;
                 case RequestMethod.ReqDelGroupOfOPC:
                     if (string.IsNullOrEmpty(ServerName) || string.IsNullOrEmpty(GroupName))
@@ -403,7 +403,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqDelGroupOfOPC.Request() { opcname = ServerName, groupname = GroupName });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqDelGroupOfOPC.Request() { opcname = ServerName, groupname = GroupName });
                     break;
                 case RequestMethod.ReqGetGroupsOfOPC:
                     if (string.IsNullOrEmpty(ServerName))
@@ -412,7 +412,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqGetGroupsOfOPC.Request() { opcname = ServerName });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqGetGroupsOfOPC.Request() { opcname = ServerName });
                     if (reverseBackParam.State)
                     {
                         ReqGetGroupsOfOPC.Response response = reverseBackParam.RData as ReqGetGroupsOfOPC.Response;
@@ -429,7 +429,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqAddItemsOfGroup.Request() { opcname = ServerName, groupname = GroupName, itemlist = new List<ReqAddItemsOfGroup.Request._itemlist>() { new ReqAddItemsOfGroup.Request._itemlist() { itemname = NodeName } } });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqAddItemsOfGroup.Request() { opcname = ServerName, groupname = GroupName, itemlist = new List<ReqAddItemsOfGroup.Request._itemlist>() { new ReqAddItemsOfGroup.Request._itemlist() { itemname = NodeName } } });
                     break;
                 case RequestMethod.ReqGetItemsOfGroup:
                     if (string.IsNullOrEmpty(ServerName) || string.IsNullOrEmpty(GroupName))
@@ -438,7 +438,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqGetItemsOfGroup.Request() { opcname = ServerName, groupname = GroupName });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqGetItemsOfGroup.Request() { opcname = ServerName, groupname = GroupName });
                     break;
                 case RequestMethod.ReqDelItemsOfGroup:
                     if (string.IsNullOrEmpty(ServerName) || string.IsNullOrEmpty(GroupName) || string.IsNullOrEmpty(NodeName))
@@ -447,7 +447,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqDelItemsOfGroup.Request() { opcname = ServerName, groupname = GroupName, itemlist = new List<ReqDelItemsOfGroup.Request._itemlist>() { new ReqDelItemsOfGroup.Request._itemlist() { itemname = NodeName } } });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqDelItemsOfGroup.Request() { opcname = ServerName, groupname = GroupName, itemlist = new List<ReqDelItemsOfGroup.Request._itemlist>() { new ReqDelItemsOfGroup.Request._itemlist() { itemname = NodeName } } });
                     break;
                 case RequestMethod.ReqReadItemsValueOfGroup:
                     if (string.IsNullOrEmpty(ServerName) || string.IsNullOrEmpty(GroupName))
@@ -456,7 +456,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqReadItemsValueOfGroup.Request() { opcname = ServerName, groupname = GroupName });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqReadItemsValueOfGroup.Request() { opcname = ServerName, groupname = GroupName });
                     break;
                 case RequestMethod.ReqGetConnectStatusOfOPC:
                     if (string.IsNullOrEmpty(ServerName))
@@ -465,7 +465,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqGetConnectStatusOfOPC.Request() { opcname = ServerName });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqGetConnectStatusOfOPC.Request() { opcname = ServerName });
                     break;
                 case RequestMethod.ReqWriteItemValue:
                     if (string.IsNullOrEmpty(ServerName) || string.IsNullOrEmpty(GroupName) || string.IsNullOrEmpty(NodeName) || string.IsNullOrEmpty(NodeValue))
@@ -474,7 +474,7 @@ namespace YSAI.Tool.Core.opc.da.http
                         RequestIsEnabled = true;
                         return;
                     }
-                    reverseBackParam = Operate.Request((int)requestMethod, new ReqWriteItemValue.Request() { opcname = ServerName, groupname = GroupName, itemname = NodeName, itemvalue = NodeValue });
+                    reverseBackParam = Operate.Request(requestMethod, new ReqWriteItemValue.Request() { opcname = ServerName, groupname = GroupName, itemname = NodeName, itemvalue = NodeValue });
                     break;
             }
             MessageOut($"{reverseBackParam.Message},用时:{reverseBackParam.RunTime} ms");