Advertisement
Guest User

Untitled

a guest
Nov 13th, 2018
135
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 17.01 KB | None | 0 0
  1. <#@ template debug="false" hostspecific="true" language="C#" #>
  2. <#@ assembly name="System.Core" #>
  3. <#@ import namespace="System.Linq" #>
  4. <#@ import namespace="System.IO" #>
  5. <#@ import namespace="System.Text" #>
  6. <#@ import namespace="System.Security" #>
  7. <#@ import namespace="System.Collections.Generic" #>
  8. <#@ import namespace="System.Collections.ObjectModel" #>
  9. <#@ output extension=".cs" #>
  10. <#
  11.     var basePath = Path.GetFullPath(Host.ResolveAssemblyReference("$(ProjectDir)"));
  12.     var structureDefinitions = ParseStructureDeclarations(basePath, @"Messaging\Channels\Ipc\Packets\*.struct");
  13.  
  14.     var blittableTypesCount = 0;
  15.     do
  16.     {
  17.         blittableTypesCount = BlittableTypeSizes.Count;
  18.  
  19.         foreach (var structureDefinition in structureDefinitions)
  20.         {
  21.             if (BlittableTypeSizes.ContainsKey(structureDefinition.Name))
  22.                 continue;
  23.             if (structureDefinition.Type != "struct")
  24.                 continue;
  25.  
  26.             var maxOffset = 0;
  27.             var offset = 0;
  28.             foreach (var field in structureDefinition.Fields)
  29.             {
  30.                 var fieldSize = 0;
  31.                 if (BlittableTypeSizes.TryGetValue(field.Type, out fieldSize) == false)
  32.                     goto nextStruct;
  33.  
  34.                 if(field.Offset > 0)
  35.                     offset = field.Offset;
  36.                
  37.                 offset += fieldSize;
  38.                 maxOffset = Math.Max(offset, maxOffset);
  39.             }
  40.  
  41.             BlittableTypeSizes[structureDefinition.Name] = maxOffset;
  42.         nextStruct:
  43.             continue;
  44.         }
  45.     } while (blittableTypesCount != BlittableTypeSizes.Count);
  46. #>//------------------------------------------------------------------------------
  47. // <auto-generated>
  48. //   This code was generated by a tool.
  49. //   Changes to this file may cause incorrect behavior and will be lost if
  50. //   the code is regenerated.
  51. // </auto-generated>
  52. //------------------------------------------------------------------------------
  53.  
  54. // ReSharper disable All
  55. using System;
  56. using System.IO;
  57. using System.Runtime.InteropServices;
  58. using System.Runtime.CompilerServices;
  59. using Pluto.Utils.Serialization.Binary;
  60.  
  61. namespace Pluto
  62. {
  63.     public static class BinarySerialiableTypes
  64.     {
  65.         public static void Register()
  66.         {
  67. <#
  68. foreach(var structure in structureDefinitions)
  69. {
  70. #>          RuntimeHelpers.RunClassConstructor(typeof(<#= @structure.Namespace #>.<#= @structure.Name #>).TypeHandle);
  71. <#
  72. }
  73. #>      }
  74.     }
  75. }
  76.  
  77. <#
  78. foreach(var structure in structureDefinitions)
  79. {
  80.     var size = 0;
  81.     var isBlittable = BlittableTypeSizes.TryGetValue(structure.Name, out size);
  82.     var offset = 0;
  83. #>
  84. namespace <#= structure.Namespace #>
  85. {
  86.     <#= string.IsNullOrWhiteSpace(structure.Description) ? "" : "/// <summary>" + SecurityElement.Escape(structure.Description.Replace("\n", ""))+ "</summary>" #>
  87.     <#= isBlittable ? "[StructLayout(LayoutKind.Explicit, Size = " + size + ", Pack = 1)]" : "" #>
  88.     public partial <#= @structure.Type #> <#= @structure.Name #>
  89.     {  
  90. <#
  91.     foreach(var field in structure.Fields)
  92.     {
  93.         if(field.Offset > 0)
  94.             offset = field.Offset;
  95.  
  96. #>      <#= isBlittable ? "[FieldOffset(" +  offset + ")]" : "" #><#= field.Type == "Bool" || field.Type == "Boolean" ? "[MarshalAs(UnmanagedType.I1)]" : "" #>
  97.         public <#= field.Type #> <#= field.Name #>;
  98. <#
  99.         var fieldSize = 0;
  100.         BlittableTypeSizes.TryGetValue(field.Type, out fieldSize);
  101.         offset += fieldSize;
  102.     }
  103. #>
  104.         static <#= @structure.Name #>()
  105.         {
  106.             TypeSerializer<<#= structure.Name #>>.Register<Serializer>();
  107.         }
  108.         public <#= structure.Name #>(<#= string.Join(", ", structure.Fields.Select(f => f.Type + " " + f.Name.ToLowerInvariant()).ToArray()) #>)
  109.         {
  110. <#
  111.     foreach(var field in structure.Fields)
  112.     {
  113. #>          this.<#= field.Name #> = <#= field.Name.ToLowerInvariant() #>;
  114. <#
  115.     }
  116. #>
  117.         }
  118.  
  119.         public override int GetHashCode()
  120.         {
  121.             return unchecked
  122.             (
  123. <#
  124.     foreach(var field in structure.Fields)
  125.     {
  126. #>              (this.<#= field.Name #> == default(<#= field.Type #>) ? 0 : this.<#= field.Name #>.GetHashCode()) <#= structure.Fields.Last() == field ? "" : "+" #>
  127. <#
  128.     }
  129. #>
  130.             );
  131.         }
  132.         public override bool Equals(object value)
  133.         {
  134.             return value is <#= structure.Name #> && this.Equals((<#= structure.Name #>)value);
  135.         }
  136.         public bool Equals(<#= structure.Name #> other)
  137.         {
  138. <#
  139.     if (structure.Type == "class")
  140.     {#>
  141.             if (other == null)
  142.                 return false;
  143.             else if (ReferenceEquals(this, other))
  144.                 return true;
  145. <#
  146.     }
  147. #>
  148.             return
  149.             (
  150. <#
  151.     foreach(var field in structure.Fields)
  152.     {
  153. #>              object.Equals(this.<#= field.Name #>, other.<#= field.Name #>)  <#= structure.Fields.Last() == field ? "" : "&&" #>
  154. <#
  155.     }
  156. #>          );
  157.         }
  158.  
  159.         public override string ToString()
  160.         {
  161.             return
  162.             (
  163.                 "<#= structure.Name #>, " +
  164. <#
  165.     foreach(var field in structure.Fields)
  166.     {
  167.         var fieldValue = "this." + field.Name;
  168.         if(field.Type.EndsWith("[]"))
  169.             fieldValue = "(this." + field.Name + " != null ? string.Join(\", \", Array.ConvertAll(this." + field.Name + ", v => Convert.ToString(v))) : \"<null>\")";
  170. #>              "<#= field.Name #>: " + <#= fieldValue #> <#= structure.Fields.Last() == field ? "" : "+ \", \" + " #>
  171. <#
  172.     }
  173. #>
  174.             );
  175.         }
  176.  
  177.         public sealed class Serializer : <#= isBlittable ? "Blittable" : "" #>TypeSerializer<<#= @structure.Name #>>
  178.         {
  179.             public override int Write(ref <#= @structure.Name #> value, BinaryWriter writer)
  180.             {
  181.                 var size = 0;
  182. <#
  183.         offset = 0;
  184.         foreach(var field in structure.Fields)
  185.         {
  186.             if(field.Offset > 0 && field.Offset != offset)
  187.             {
  188.                 if (field.Offset < offset) throw new NotSupportedException("Negative field offset is not supported.");
  189.                 var hole = field.Offset - offset;
  190. #>              size += <#= hole #>;
  191. <#
  192.                 while (hole > 0)
  193.                 {
  194.                     var holeType = "";
  195.                     switch(hole)
  196.                     {
  197.                         case 1:  holeType = "Byte"; hole -= 1; break;
  198.                         case 2:
  199.                         case 3:  holeType = "Int16"; hole -= 2; break;
  200.                         case 4:  
  201.                         case 5:  
  202.                         case 6:  
  203.                         case 7: holeType = "Int32"; hole -= 4; break;
  204.                         default: holeType = "Int64"; hole -= 8; break;
  205.                     }
  206. #>              writer.Write((<#= holeType #>)0);
  207. <#
  208.                 }
  209.                 offset = field.Offset;
  210.             }
  211.  
  212. #>
  213.                 size += TypeSerializer<<#= field.Type #>>.Instance.Write(ref value.<#= field.Name #>, writer);
  214. <#
  215.             var fieldSize = 0;
  216.             BlittableTypeSizes.TryGetValue(field.Type, out fieldSize);
  217.             offset += fieldSize;
  218.         }
  219. #>
  220.                 return size;
  221.             }
  222.  
  223.             public override int Write(ref <#= @structure.Name #> value, WriteBuffer writeBuffer)
  224.             {
  225. <#
  226.     if (!isBlittable)
  227.     {
  228. #>              var size = 0;
  229. <#
  230.         foreach(var field in structure.Fields)
  231.         {
  232.             if (field.Offset > 0 && field.Offset != offset)
  233.             {
  234.                 if (field.Offset < offset) throw new NotSupportedException("Negative field offset is not supported.");
  235.                 var hole = field.Offset - offset;
  236. #>              size += <#= hole #>;
  237.                 writer.WriteByte(0, <#= hole #>);
  238. <#
  239.                 offset = field.Offset;
  240.             }
  241.  
  242. #>              size += TypeSerializer<<#= field.Type #>>.Instance.Write(ref value.<#= field.Name #>, writeBuffer);
  243. <#
  244.         }
  245. #>
  246.                 return size;
  247. <#
  248.     }
  249.     else
  250.     {
  251. #>
  252.                 writeBuffer.EnsureRange(<#= size #>);
  253.  
  254.                 var buffer = writeBuffer.Buffer;
  255.                 unsafe
  256.                 {
  257.                     fixed (byte* b = buffer)
  258.                         *((<#= @structure.Name #>*)(b + writeBuffer.Offset)) = value;
  259.                 }
  260.                 writeBuffer.Offset += <#= size #>;
  261.                 writeBuffer.BytesAvailable -= <#= size #>;
  262.  
  263.                 return <#= size #>;
  264. <#
  265.     }
  266. #>
  267.             }
  268.  
  269.             public override int Read(out <#= @structure.Name #> value, BinaryReader reader)
  270.             {
  271.                 var size = 0;
  272. <#
  273.         offset = 0;
  274.         foreach(var field in structure.Fields)
  275.         {
  276.             if(field.Offset > 0 && field.Offset != offset)
  277.             {
  278.                 if (field.Offset < offset) throw new NotSupportedException("Negative field offset is not supported.");
  279.                 var hole = field.Offset - offset;
  280. #>
  281.                 size += <#= hole #>;
  282. <#
  283.                 while (hole > 0)
  284.                 {
  285.                     var holeType = "";
  286.                     switch(hole)
  287.                     {
  288.                         case 1:  holeType = "Byte"; hole -= 1; break;
  289.                         case 2:
  290.                         case 3:  holeType = "Int16"; hole -= 2; break;
  291.                         case 4:  
  292.                         case 5:  
  293.                         case 6:  
  294.                         case 7: holeType = "Int32"; hole -= 4; break;
  295.                         default: holeType = "Int64"; hole -= 8; break;
  296.                     }
  297. #>              reader.Read<#= holeType #>();
  298. <#
  299.                 }
  300.                 offset = field.Offset;
  301.             }
  302.  
  303. #>
  304.                 size += TypeSerializer<<#= field.Type #>>.Instance.Read(out value.<#= field.Name #>, reader);
  305. <#
  306.             var fieldSize = 0;
  307.             BlittableTypeSizes.TryGetValue(field.Type, out fieldSize);
  308.             offset += fieldSize;
  309.         }
  310. #>
  311.                 return size;
  312.             }
  313.  
  314.             public override int Read(out <#= @structure.Name #> value, ReadBuffer readBuffer)
  315.             {
  316. <#
  317.     if (!isBlittable)
  318.     {
  319. #>              var size = 0;
  320. <#
  321.         foreach(var field in structure.Fields)
  322.         {
  323.             if (field.Offset > 0 && field.Offset != offset)
  324.             {
  325.                 if (field.Offset < offset) throw new NotSupportedException("Negative field offset is not supported.");
  326.                 var hole = field.Offset - offset;
  327. #>              size += <#= hole #>;
  328.                 readBuffer.SkipBytes(<#= hole #>);
  329. <#
  330.                 offset = field.Offset;
  331.             }
  332.  
  333. #>
  334.                 size += TypeSerializer<<#= field.Type #>>.Instance.Read(out value.<#= field.Name #>, readBuffer);
  335. <#
  336.         }
  337. #>
  338.                 return size;
  339. <#
  340.     }
  341.     else
  342.     {
  343. #>
  344.                 readBuffer.EnsureRange(<#= size #>);
  345.  
  346.                 var buffer = readBuffer.Buffer;
  347.                 unsafe
  348.                 {
  349.                     fixed (byte* b = buffer)
  350.                         value = *((<#= @structure.Name #>*)(b + readBuffer.Offset));
  351.                 }
  352.                 readBuffer.Offset += <#= size #>;
  353.                 readBuffer.BytesAvailable -= <#= size #>;
  354.  
  355.                 return <#= size #>;
  356. <#
  357.     }
  358. #>
  359.             }
  360.  
  361.             public override int Measure(ref <#= @structure.Name #> value)
  362.             {
  363. <#
  364.     if (!isBlittable)
  365.     {
  366. #>
  367.                 var size = 0;
  368. <#
  369.         foreach(var field in structure.Fields)
  370.         {
  371.             if (field.Offset > 0 && field.Offset != offset)
  372.             {
  373.                 if (field.Offset < offset) throw new NotSupportedException("Negative field offset is not supported.");
  374.                 var hole = field.Offset - offset;
  375. #>              size += <#= hole #>;
  376. <#
  377.                 offset = field.Offset;
  378.             }
  379.  
  380. #>
  381.                 size += TypeSerializer<<#= field.Type #>>.Instance.Measure(ref value.<#= field.Name #>);
  382. <#
  383.         }
  384. #>
  385.                 return size;
  386. <#
  387.     }
  388.     else
  389.     {
  390. #>
  391.                 return <#= size #>;
  392. <#
  393.     }
  394. #>
  395.             }
  396.         }
  397.     }
  398. }
  399. <#
  400. }
  401. #>
  402.  
  403.  
  404. <#+
  405. private List<StructureDefinition> ParseStructureDeclarations(string basePath, string pattern)
  406. {
  407.     var files = Directory.GetFiles(basePath, pattern, SearchOption.AllDirectories);
  408.     var structures = new List<StructureDefinition>();
  409.  
  410.     const int STATE_START = 0;
  411.     const int STATE_DEFINITION = 1;
  412.     const int STATE_NAME = 2;
  413.     const int STATE_STRUCT_BODY_START = 3;
  414.     const int STATE_STRUCT_BODY_FIELD_TYPE = 4;
  415.     const int STATE_STRUCT_BODY_FIELD_NAME = 5;
  416.     const int STATE_STRUCT_BODY_FIELD_OFFSET_START = 6;
  417.     const int STATE_STRUCT_BODY_FIELD_OFFSET = 7;
  418.     const int STATE_STRUCT_BODY_FIELD_END = 8;
  419.     const int STATE_STRUCT_BODY_FIELD_COMPLETE = 9;
  420.     const int STATE_STRUCT_COMPLETE = 10;
  421.  
  422.     foreach (var file in files)
  423.     {
  424.         var fileName = Path.GetFileName(file);
  425.         var content = File.ReadAllText(file, Encoding.UTF8);
  426.         var state = STATE_START;
  427.         var structDescription = default(string);
  428.         var structName = default(string);
  429.         var structNamespace = "Pluto." + Path.GetDirectoryName(file).Substring(basePath.Length).Replace('\\', '.').Replace('/', '.');
  430.         var structType = default(string);
  431.         var fieldType = default(string);
  432.         var fieldName = default(string);
  433.         var fieldOffset = default(string);
  434.         var fields = new List<FieldDefinition>();
  435.         var chars = new StringBuilder();
  436.         for (var offset = 0; offset < content.Length; offset++)
  437.         {
  438.             var @char = content[offset];
  439.             switch (state)
  440.             {
  441.                 case STATE_START:
  442.                     if (char.IsWhiteSpace(@char))
  443.                         continue;
  444.  
  445.                     chars.Append(@char);
  446.                     state = STATE_DEFINITION;
  447.                     break;
  448.                 case STATE_DEFINITION:
  449.                     if (chars.Length > 0 && char.IsWhiteSpace(@char))
  450.                     {
  451.                         structType = chars.ToString();
  452.                         switch (structType)
  453.                         {
  454.                             case "struct":
  455.                             case "class": state = STATE_NAME; break;
  456.                             default: throw new InvalidOperationException(string.Format("Unknown definition '{0}' at '{1}:{2}'.", chars.ToString(), fileName, offset));
  457.                         }
  458.                         chars.Length = 0;
  459.                         continue;
  460.                     }
  461.                     else if (char.IsWhiteSpace(@char))
  462.                         continue;
  463.  
  464.                     chars.Append(@char);
  465.                     break;
  466.                 case STATE_NAME:
  467.                     if (chars.Length > 0 && (char.IsWhiteSpace(@char) || @char == '{'))
  468.                     {
  469.                         state = @char == '{' ? STATE_STRUCT_BODY_FIELD_TYPE : STATE_STRUCT_BODY_START;
  470.                         structName = chars.ToString();
  471.                         chars.Length = 0;
  472.                         continue;
  473.                     }
  474.                     else if (char.IsWhiteSpace(@char))
  475.                         continue;
  476.  
  477.                     chars.Append(@char);
  478.                     break;
  479.                 case STATE_STRUCT_BODY_START:
  480.                     if (char.IsWhiteSpace(@char))
  481.                         continue;
  482.                     else if (@char == '{')
  483.                         state = STATE_STRUCT_BODY_FIELD_TYPE;
  484.                     else
  485.                         throw new InvalidOperationException(string.Format("Invalid syntax '{0}'  at '{1}:{2}'.", @char, fileName, offset));
  486.                     break;
  487.                 case STATE_STRUCT_BODY_FIELD_TYPE:
  488.                     if (chars.Length > 0 && char.IsWhiteSpace(@char))
  489.                     {
  490.                         state = STATE_STRUCT_BODY_FIELD_NAME;
  491.                         fieldType = chars.ToString();
  492.                         chars.Length = 0;
  493.                     }
  494.                     else if (@char == '}')
  495.                         state = STATE_STRUCT_COMPLETE;
  496.                     else if (char.IsWhiteSpace(@char))
  497.                         continue;
  498.                     else
  499.                         chars.Append(@char);
  500.                     break;
  501.                 case STATE_STRUCT_BODY_FIELD_NAME:
  502.                     if (chars.Length > 0 && (char.IsWhiteSpace(@char) || @char == ':' || @char == ',' || @char == '}'))
  503.                     {
  504.                         if (char.IsWhiteSpace(@char))
  505.                             state = STATE_STRUCT_BODY_FIELD_OFFSET_START;
  506.                         else if (@char == ':')
  507.                             state = STATE_STRUCT_BODY_FIELD_OFFSET;
  508.                         else
  509.                             state = STATE_STRUCT_BODY_FIELD_COMPLETE;
  510.  
  511.                         fieldName = chars.ToString();
  512.                         chars.Length = 0;
  513.                     }
  514.                     else if (char.IsWhiteSpace(@char))
  515.                         continue;
  516.                     else
  517.                         chars.Append(@char);
  518.                     break;
  519.                 case STATE_STRUCT_BODY_FIELD_OFFSET_START:
  520.                     if (char.IsWhiteSpace(@char))
  521.                         continue;
  522.                     else if (@char == ':')
  523.                         state = STATE_STRUCT_BODY_FIELD_OFFSET;
  524.                     else if (@char == ',' || @char == '}')
  525.                         state = STATE_STRUCT_BODY_FIELD_COMPLETE;
  526.                     else
  527.                         throw new InvalidOperationException(string.Format("Invalid syntax '{0}' at '{1}:{2}'.", @char, fileName, offset));
  528.                     break;
  529.                 case STATE_STRUCT_BODY_FIELD_OFFSET:
  530.                     if (chars.Length > 0 && (char.IsWhiteSpace(@char) || @char == ',' || @char == '}'))
  531.                     {
  532.                         if (char.IsWhiteSpace(@char))
  533.                             state = STATE_STRUCT_BODY_FIELD_END;
  534.                         else
  535.                             state = STATE_STRUCT_BODY_FIELD_COMPLETE;
  536.  
  537.                         fieldOffset = chars.ToString();
  538.                         chars.Length = 0;
  539.                     }
  540.                     else if (char.IsWhiteSpace(@char))
  541.                         continue;
  542.                     else
  543.                         chars.Append(@char);
  544.                     break;
  545.                 case STATE_STRUCT_BODY_FIELD_END:
  546.                     if (char.IsWhiteSpace(@char))
  547.                         continue;
  548.                     else if (@char == ',' || @char == '}')
  549.                         state = STATE_STRUCT_BODY_FIELD_COMPLETE;
  550.                     else
  551.                         throw new InvalidOperationException(string.Format("Invalid syntax '{0}' at '{1}:{2}'.", @char, fileName, offset));
  552.                     break;
  553.             }
  554.  
  555.             if (state == STATE_STRUCT_BODY_FIELD_COMPLETE)
  556.             {
  557.                 fields.Add(new FieldDefinition(fieldName, fieldType, string.IsNullOrEmpty(fieldOffset) ? -1 : int.Parse(fieldOffset)));
  558.                 fieldName = null;
  559.                 fieldType = null;
  560.                 fieldOffset = null;
  561.  
  562.                 if (@char == '}')
  563.                     state = STATE_STRUCT_COMPLETE;
  564.                 else if (@char == ',')
  565.                     state = STATE_STRUCT_BODY_FIELD_TYPE;
  566.                 else
  567.                     state = STATE_STRUCT_BODY_FIELD_END;
  568.             }
  569.  
  570.             if (state == STATE_STRUCT_COMPLETE)
  571.             {
  572.                 structures.Add(new StructureDefinition(structType, structNamespace, structName, structDescription, fields));
  573.                 state = STATE_START;
  574.             }
  575.         }
  576.     }
  577.  
  578.     return structures;
  579. }
  580.  
  581. private readonly Dictionary<string, int> BlittableTypeSizes = new Dictionary<string, int>(StringComparer.Ordinal)
  582. {
  583.     {"Boolean", 1},
  584.     {"bool", 1},
  585.     {"Byte", 1},
  586.     {"byte", 1},
  587.     {"SByte", 1},
  588.     {"sbyte", 1},
  589.     {"Int16", 2},
  590.     {"short", 2},
  591.     {"UInt16", 2},
  592.     {"ushort", 2},
  593.     {"Int32", 4},
  594.     {"int", 4},
  595.     {"UInt32", 4},
  596.     {"uint", 4},
  597.     {"Int64", 8},
  598.     {"long", 8},
  599.     {"UInt64", 8},
  600.     {"ulong", 8},
  601.     {"Single", 4},
  602.     {"float", 4},
  603.     {"Double", 8},
  604.     {"double", 8},
  605.     {"Сhar", 2},
  606.     {"char", 2},
  607.     {"Guid", 16},
  608.     {"TimeSpan", 8},
  609. };
  610.  
  611. private class StructureDefinition
  612. {
  613.     public readonly string Type;
  614.     public readonly string Name;
  615.     public readonly string Namespace;
  616.     public readonly string Description;
  617.     public ReadOnlyCollection<FieldDefinition> Fields;
  618.  
  619.     public StructureDefinition(string type, string @namespace, string name, string description, List<FieldDefinition> fields)
  620.     {
  621.         this.Type = type;
  622.         this.Namespace = @namespace;
  623.         this.Name = name;
  624.         this.Description = description;
  625.         this.Fields = new ReadOnlyCollection<FieldDefinition>(fields);
  626.     }
  627.  
  628.     public override string ToString()
  629.     {
  630.         return string.Format("struct {0} {{ {1} }}", this.Name, string.Join(", ", this.Fields));
  631.     }
  632. }
  633. private class FieldDefinition
  634. {
  635.     public readonly string Name;
  636.     public readonly string Type;
  637.     public readonly int Offset;
  638.  
  639.     public FieldDefinition(string name, string type, int offset)
  640.     {
  641.         this.Name = name;
  642.         this.Type = type;
  643.         this.Offset = offset;
  644.     }
  645.  
  646.     public override string ToString()
  647.     {
  648.         if (this.Offset < 0)
  649.             return this.Type + " " + this.Name;
  650.         else
  651.             return this.Type + " " + this.Name + ": " + this.Offset;
  652.     }
  653. }
  654. #>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement