1 /*
2  * hunt-time: A time library for D programming language.
3  *
4  * Copyright (C) 2015-2018 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.time.zone.ZoneOffsetTransitionRule;
13 
14 import hunt.time.temporal.TemporalAdjusters;
15 
16 import hunt.stream.DataInput;
17 import hunt.stream.DataOutput;
18 import hunt.Exceptions;
19 
20 import hunt.time.zone.Ser;
21 import hunt.stream.Common;
22 import hunt.time.DayOfWeek;
23 import hunt.time.LocalDate;
24 import hunt.time.LocalDateTime;
25 import hunt.time.LocalTime;
26 import hunt.time.Month;
27 import hunt.time.ZoneOffset;
28 import hunt.time.chrono.IsoChronology;
29 import hunt.time.zone.ZoneOffsetTransition;
30 import hunt.util.StringBuilder;
31 import hunt.time.util.Common;
32 
33 import hunt.util.Common;
34 // import hunt.serialization.JsonSerializer;
35 
36 
37 /**
38  * A rule expressing how to create a transition.
39  * !(p)
40  * This class allows rules for identifying future transitions to be expressed.
41  * A rule might be written _in many forms:
42  * !(ul)
43  * !(li)the 16th March
44  * !(li)the Sunday on or after the 16th March
45  * !(li)the Sunday on or before the 16th March
46  * !(li)the last Sunday _in February
47  * </ul>
48  * These different rule types can be expressed and queried.
49  *
50  * @implSpec
51  * This class is immutable and thread-safe.
52  *
53  * @since 1.8
54  */
55 public final class ZoneOffsetTransitionRule { //  : Serializable
56 
57 
58     /**
59      * The month of the month-day of the first day of the cutover week.
60      * The actual date will be adjusted by the dowChange field.
61      */
62     private  Month month;
63     /**
64      * The day-of-month of the month-day of the cutover week.
65      * If positive, it is the start of the week where the cutover can occur.
66      * If negative, it represents the end of the week where cutover can occur.
67      * The value is the number of days from the end of the month, such that
68      * {@code -1} is the last day of the month, {@code -2} is the second
69      * to last day, and so on.
70      */
71     private  byte dom;
72     /**
73      * The cutover day-of-week, null to retain the day-of-month.
74      */
75     private  DayOfWeek dow;
76     /**
77      * The cutover time _in the 'before' offset.
78      */
79     private  LocalTime time;
80     /**
81      * Whether the cutover time is midnight at the end of day.
82      */
83     private  bool timeEndOfDay;
84     /**
85      * The definition of how the local time should be interpreted.
86      */
87     private  TimeDefinition timeDefinition;
88     /**
89      * The standard offset at the cutover.
90      */
91     private  ZoneOffset standardOffset;
92     /**
93      * The offset before the cutover.
94      */
95     private  ZoneOffset offsetBefore;
96     /**
97      * The offset after the cutover.
98      */
99     private  ZoneOffset offsetAfter;
100 
101     /**
102      * Obtains an instance defining the yearly rule to create transitions between two offsets.
103      * !(p)
104      * Applications should normally obtain an instance from {@link ZoneRules}.
105      * This factory is only intended for use when creating {@link ZoneRules}.
106      *
107      * @param month  the month of the month-day of the first day of the cutover week, not null
108      * @param dayOfMonthIndicator  the day of the month-day of the cutover week, positive if the week is that
109      *  day or later, negative if the week is that day or earlier, counting from the last day of the month,
110      *  from -28 to 31 excluding 0
111      * @param dayOfWeek  the required day-of-week, null if the month-day should not be changed
112      * @param time  the cutover time _in the 'before' offset, not null
113      * @param timeEndOfDay  whether the time is midnight at the end of day
114      * @param timeDefnition  how to interpret the cutover
115      * @param standardOffset  the standard offset _in force at the cutover, not null
116      * @param offsetBefore  the offset before the cutover, not null
117      * @param offsetAfter  the offset after the cutover, not null
118      * @return the rule, not null
119      * @throws IllegalArgumentException if the day of month indicator is invalid
120      * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
121      * @throws IllegalArgumentException if {@code time.getNano()} returns non-zero value
122      */
123     public static ZoneOffsetTransitionRule of(
124             Month month,
125             int dayOfMonthIndicator,
126             DayOfWeek dayOfWeek,
127             LocalTime time,
128             bool timeEndOfDay,
129             TimeDefinition timeDefnition,
130             ZoneOffset standardOffset,
131             ZoneOffset offsetBefore,
132             ZoneOffset offsetAfter) {
133         assert(month, "month");
134         assert(time, "time");
135         // assert(timeDefnition, "timeDefnition");
136         assert(standardOffset, "standardOffset");
137         assert(offsetBefore, "offsetBefore");
138         assert(offsetAfter, "offsetAfter");
139         if (dayOfMonthIndicator < -28 || dayOfMonthIndicator > 31 || dayOfMonthIndicator == 0) {
140             throw new IllegalArgumentException("Day of month indicator must be between -28 and 31 inclusive excluding zero");
141         }
142         if (timeEndOfDay && (time == LocalTime.MIDNIGHT) == false) {
143             throw new IllegalArgumentException("Time must be midnight when end of day flag is true");
144         }
145         if (time.getNano() != 0) {
146             throw new IllegalArgumentException("Time's nano-of-second must be zero");
147         }
148         return new ZoneOffsetTransitionRule(month, dayOfMonthIndicator, dayOfWeek, time, timeEndOfDay, timeDefnition, standardOffset, offsetBefore, offsetAfter);
149     }
150 
151     /**
152      * Creates an instance defining the yearly rule to create transitions between two offsets.
153      *
154      * @param month  the month of the month-day of the first day of the cutover week, not null
155      * @param dayOfMonthIndicator  the day of the month-day of the cutover week, positive if the week is that
156      *  day or later, negative if the week is that day or earlier, counting from the last day of the month,
157      *  from -28 to 31 excluding 0
158      * @param dayOfWeek  the required day-of-week, null if the month-day should not be changed
159      * @param time  the cutover time _in the 'before' offset, not null
160      * @param timeEndOfDay  whether the time is midnight at the end of day
161      * @param timeDefnition  how to interpret the cutover
162      * @param standardOffset  the standard offset _in force at the cutover, not null
163      * @param offsetBefore  the offset before the cutover, not null
164      * @param offsetAfter  the offset after the cutover, not null
165      * @throws IllegalArgumentException if the day of month indicator is invalid
166      * @throws IllegalArgumentException if the end of day flag is true when the time is not midnight
167      */
168     this(
169             Month month,
170             int dayOfMonthIndicator,
171             DayOfWeek dayOfWeek,
172             LocalTime time,
173             bool timeEndOfDay,
174             TimeDefinition timeDefnition,
175             ZoneOffset standardOffset,
176             ZoneOffset offsetBefore,
177             ZoneOffset offsetAfter) {
178         assert(time.getNano() == 0);
179         this.month = month;
180         this.dom = cast(byte) dayOfMonthIndicator;
181         this.dow = dayOfWeek;
182         this.time = time;
183         this.timeEndOfDay = timeEndOfDay;
184         this.timeDefinition = timeDefnition;
185         this.standardOffset = standardOffset;
186         this.offsetBefore = offsetBefore;
187         this.offsetAfter = offsetAfter;
188     }
189 
190     //-----------------------------------------------------------------------
191     /**
192      * Defend against malicious streams.
193      *
194      * @param s the stream to read
195      * @throws InvalidObjectException always
196      */
197      ///@gxc
198     // private void readObject(ObjectInputStream s) /*throws InvalidObjectException*/ {
199     //     throw new InvalidObjectException("Deserialization via serialization delegate");
200     // }
201 
202     /**
203      * Writes the object using a
204      * <a href="{@docRoot}/serialized-form.html#hunt.time.zone.Ser">dedicated serialized form</a>.
205      * @serialData
206      * Refer to the serialized form of
207      * <a href="{@docRoot}/serialized-form.html#hunt.time.zone.ZoneRules">ZoneRules.writeReplace</a>
208      * for the encoding of epoch seconds and offsets.
209      * <pre style="font-size:1.0em">{@code
210      *
211      *      _out.writeByte(3);                // identifies a ZoneOffsetTransition
212      *      final int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
213      *      final int stdOffset = standardOffset.getTotalSeconds();
214      *      final int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
215      *      final int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
216      *      final int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
217      *      final int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
218      *      final int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
219      *      final int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
220      *      final int dowByte = (dow is null ? 0 : dow.getValue());
221      *      int b = (month.getValue() << 28) +          // 4 bits
222      *              ((dom + 32) << 22) +                // 6 bits
223      *              (dowByte << 19) +                   // 3 bits
224      *              (timeByte << 14) +                  // 5 bits
225      *              (timeDefinition.ordinal() << 12) +  // 2 bits
226      *              (stdOffsetByte << 4) +              // 8 bits
227      *              (beforeByte << 2) +                 // 2 bits
228      *              afterByte;                          // 2 bits
229      *      _out.writeInt(b);
230      *      if (timeByte == 31) {
231      *          _out.writeInt(timeSecs);
232      *      }
233      *      if (stdOffsetByte == 255) {
234      *          _out.writeInt(stdOffset);
235      *      }
236      *      if (beforeByte == 3) {
237      *          _out.writeInt(offsetBefore.getTotalSeconds());
238      *      }
239      *      if (afterByte == 3) {
240      *          _out.writeInt(offsetAfter.getTotalSeconds());
241      *      }
242      * }
243      * </pre>
244      *
245      * @return the replacing object, not null
246      */
247     private Object writeReplace() {
248         return new Ser(Ser.ZOTRULE, this);
249     }
250 
251     /**
252      * Writes the state to the stream.
253      *
254      * @param _out  the output stream, not null
255      * @throws IOException if an error occurs
256      */
257     void writeExternal(DataOutput _out) /*throws IOException*/ {
258         int timeSecs = (timeEndOfDay ? 86400 : time.toSecondOfDay());
259         int stdOffset = standardOffset.getTotalSeconds();
260         int beforeDiff = offsetBefore.getTotalSeconds() - stdOffset;
261         int afterDiff = offsetAfter.getTotalSeconds() - stdOffset;
262         int timeByte = (timeSecs % 3600 == 0 ? (timeEndOfDay ? 24 : time.getHour()) : 31);
263         int stdOffsetByte = (stdOffset % 900 == 0 ? stdOffset / 900 + 128 : 255);
264         int beforeByte = (beforeDiff == 0 || beforeDiff == 1800 || beforeDiff == 3600 ? beforeDiff / 1800 : 3);
265         int afterByte = (afterDiff == 0 || afterDiff == 1800 || afterDiff == 3600 ? afterDiff / 1800 : 3);
266         int dowByte = (dow is null ? 0 : dow.getValue());
267         int b = (month.getValue() << 28) +          // 4 bits
268                 ((dom + 32) << 22) +                // 6 bits
269                 (dowByte << 19) +                   // 3 bits
270                 (timeByte << 14) +                  // 5 bits
271                 (timeDefinition.ordinal() << 12) +  // 2 bits
272                 (stdOffsetByte << 4) +              // 8 bits
273                 (beforeByte << 2) +                 // 2 bits
274                 afterByte;                          // 2 bits
275         _out.writeInt(b);
276         if (timeByte == 31) {
277             _out.writeInt(timeSecs);
278         }
279         if (stdOffsetByte == 255) {
280             _out.writeInt(stdOffset);
281         }
282         if (beforeByte == 3) {
283             _out.writeInt(offsetBefore.getTotalSeconds());
284         }
285         if (afterByte == 3) {
286             _out.writeInt(offsetAfter.getTotalSeconds());
287         }
288     }
289 
290     /**
291      * Reads the state from the stream.
292      *
293      * @param _in  the input stream, not null
294      * @return the created object, not null
295      * @throws IOException if an error occurs
296      */
297     static ZoneOffsetTransitionRule readExternal(DataInput _in) /*throws IOException*/ {
298         int data = _in.readInt();
299         Month month = Month.of(data >>> 28);
300         int dom = ((data & (63 << 22)) >>> 22) - 32;
301         int dowByte = (data & (7 << 19)) >>> 19;
302         DayOfWeek dow = dowByte == 0 ? null : DayOfWeek.of(dowByte);
303         int timeByte = (data & (31 << 14)) >>> 14;
304         TimeDefinition defn = TimeDefinition.values()[(data & (3 << 12)) >>> 12];
305         int stdByte = (data & (255 << 4)) >>> 4;
306         int beforeByte = (data & (3 << 2)) >>> 2;
307         int afterByte = (data & 3);
308         LocalTime time = (timeByte == 31 ? LocalTime.ofSecondOfDay(_in.readInt()) : LocalTime.of(timeByte % 24, 0));
309         ZoneOffset std = (stdByte == 255 ? ZoneOffset.ofTotalSeconds(_in.readInt()) : ZoneOffset.ofTotalSeconds((stdByte - 128) * 900));
310         ZoneOffset before = (beforeByte == 3 ? ZoneOffset.ofTotalSeconds(_in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + beforeByte * 1800));
311         ZoneOffset after = (afterByte == 3 ? ZoneOffset.ofTotalSeconds(_in.readInt()) : ZoneOffset.ofTotalSeconds(std.getTotalSeconds() + afterByte * 1800));
312         return ZoneOffsetTransitionRule.of(month, dom, dow, time, timeByte == 24, defn, std, before, after);
313     }
314 
315     //-----------------------------------------------------------------------
316     /**
317      * Gets the month of the transition.
318      * !(p)
319      * If the rule defines an exact date then the month is the month of that date.
320      * !(p)
321      * If the rule defines a week where the transition might occur, then the month
322      * if the month of either the earliest or latest possible date of the cutover.
323      *
324      * @return the month of the transition, not null
325      */
326     public Month getMonth() {
327         return month;
328     }
329 
330     /**
331      * Gets the indicator of the day-of-month of the transition.
332      * !(p)
333      * If the rule defines an exact date then the day is the month of that date.
334      * !(p)
335      * If the rule defines a week where the transition might occur, then the day
336      * defines either the start of the end of the transition week.
337      * !(p)
338      * If the value is positive, then it represents a normal day-of-month, and is the
339      * earliest possible date that the transition can be.
340      * The date may refer to 29th February which should be treated as 1st March _in non-leap years.
341      * !(p)
342      * If the value is negative, then it represents the number of days back from the
343      * end of the month where {@code -1} is the last day of the month.
344      * In this case, the day identified is the latest possible date that the transition can be.
345      *
346      * @return the day-of-month indicator, from -28 to 31 excluding 0
347      */
348     public int getDayOfMonthIndicator() {
349         return dom;
350     }
351 
352     /**
353      * Gets the day-of-week of the transition.
354      * !(p)
355      * If the rule defines an exact date then this returns null.
356      * !(p)
357      * If the rule defines a week where the cutover might occur, then this method
358      * returns the day-of-week that the month-day will be adjusted to.
359      * If the day is positive then the adjustment is later.
360      * If the day is negative then the adjustment is earlier.
361      *
362      * @return the day-of-week that the transition occurs, null if the rule defines an exact date
363      */
364     public DayOfWeek getDayOfWeek() {
365         return dow;
366     }
367 
368     /**
369      * Gets the local time of day of the transition which must be checked with
370      * {@link #isMidnightEndOfDay()}.
371      * !(p)
372      * The time is converted into an instant using the time definition.
373      *
374      * @return the local time of day of the transition, not null
375      */
376     public LocalTime getLocalTime() {
377         return time;
378     }
379 
380     /**
381      * Is the transition local time midnight at the end of day.
382      * !(p)
383      * The transition may be represented as occurring at 24:00.
384      *
385      * @return whether a local time of midnight is at the start or end of the day
386      */
387     public bool isMidnightEndOfDay() {
388         return timeEndOfDay;
389     }
390 
391     /**
392      * Gets the time definition, specifying how to convert the time to an instant.
393      * !(p)
394      * The local time can be converted to an instant using the standard offset,
395      * the wall offset or UTC.
396      *
397      * @return the time definition, not null
398      */
399     public TimeDefinition getTimeDefinition() {
400         return timeDefinition;
401     }
402 
403     /**
404      * Gets the standard offset _in force at the transition.
405      *
406      * @return the standard offset, not null
407      */
408     public ZoneOffset getStandardOffset() {
409         return standardOffset;
410     }
411 
412     /**
413      * Gets the offset before the transition.
414      *
415      * @return the offset before, not null
416      */
417     public ZoneOffset getOffsetBefore() {
418         return offsetBefore;
419     }
420 
421     /**
422      * Gets the offset after the transition.
423      *
424      * @return the offset after, not null
425      */
426     public ZoneOffset getOffsetAfter() {
427         return offsetAfter;
428     }
429 
430     //-----------------------------------------------------------------------
431     /**
432      * Creates a transition instance for the specified year.
433      * !(p)
434      * Calculations are performed using the ISO-8601 chronology.
435      *
436      * @param year  the year to create a transition for, not null
437      * @return the transition instance, not null
438      */
439     public ZoneOffsetTransition createTransition(int year) {
440         LocalDate date;
441         if (dom < 0) {
442             date = LocalDate.of(year, month, month.length(IsoChronology.INSTANCE.isLeapYear(year)) + 1 + dom);
443             if (dow !is null) {
444                 date = date._with(TemporalAdjusters.previousOrSame(dow));
445             }
446         } else {
447             date = LocalDate.of(year, month, dom);
448             if (dow !is null) {
449                 date = date._with(TemporalAdjusters.nextOrSame(dow));
450             }
451         }
452         if (timeEndOfDay) {
453             date = date.plusDays(1);
454         }
455         LocalDateTime localDT = LocalDateTime.of(date, time);
456         LocalDateTime transition = timeDefinition.createDateTime(localDT, standardOffset, offsetBefore);
457         return new ZoneOffsetTransition(transition, offsetBefore, offsetAfter);
458     }
459 
460     //-----------------------------------------------------------------------
461     /**
462      * Checks if this object equals another.
463      * !(p)
464      * The entire state of the object is compared.
465      *
466      * @param otherRule  the other object to compare to, null returns false
467      * @return true if equal
468      */
469     override
470     public bool opEquals(Object otherRule) {
471         if (otherRule == this) {
472             return true;
473         }
474         if (cast(ZoneOffsetTransitionRule)(otherRule) !is null) {
475             ZoneOffsetTransitionRule other = cast(ZoneOffsetTransitionRule) otherRule;
476             return month == other.month && dom == other.dom && dow == other.dow &&
477                 timeDefinition == other.timeDefinition &&
478                 (time == other.time) &&
479                 timeEndOfDay == other.timeEndOfDay &&
480                 (standardOffset == other.standardOffset) &&
481                 (offsetBefore == other.offsetBefore) &&
482                 (offsetAfter == other.offsetAfter);
483         }
484         return false;
485     }
486 
487     /**
488      * Returns a suitable hash code.
489      *
490      * @return the hash code
491      */
492     override
493     public size_t toHash() @trusted nothrow {
494         try{
495             int hash = ((time.toSecondOfDay() + (timeEndOfDay ? 1 : 0)) << 15) +
496                 (month.ordinal() << 11) + ((dom + 32) << 5) +
497                 ((dow is null ? 7 : dow.ordinal()) << 2) + (timeDefinition.ordinal());
498             return hash ^ standardOffset.toHash() ^
499                 offsetBefore.toHash() ^ offsetAfter.toHash();
500         }catch(Exception e){}
501         return int.init;
502     }
503 
504     //-----------------------------------------------------------------------
505     /**
506      * Returns a string describing this object.
507      *
508      * @return a string for debugging, not null
509      */
510     override
511     public string toString() {
512         StringBuilder buf = new StringBuilder();
513         buf.append("TransitionRule[")
514             .append(offsetBefore.compareTo(offsetAfter) > 0 ? "Gap " : "Overlap ")
515             .append(offsetBefore.toString).append(" to ").append(offsetAfter).append(", ");
516         if (dow !is null) {
517             if (dom == -1) {
518                 buf.append(dow.name()).append(" on or before last day of ").append(month.name());
519             } else if (dom < 0) {
520                 buf.append(dow.name()).append(" on or before last day minus ").append(-(cast(int)dom) - 1).append(" of ").append(month.name());
521             } else {
522                 buf.append(dow.name()).append(" on or after ").append(month.name()).append(' ').append(dom);
523             }
524         } else {
525             buf.append(month.name()).append(' ').append(dom);
526         }
527         buf.append(" at ").append(timeEndOfDay ? "24:00" : time.toString())
528             .append(" ").append(timeDefinition)
529             .append(", standard offset ").append(standardOffset)
530             .append(']');
531         return buf.toString();
532     }
533 
534     //-----------------------------------------------------------------------
535     /**
536      * A definition of the way a local time can be converted to the actual
537      * transition date-time.
538      * !(p)
539      * Time zone rules are expressed _in one of three ways:
540      * !(ul)
541      * !(li)Relative to UTC</li>
542      * !(li)Relative to the standard offset _in force</li>
543      * !(li)Relative to the wall offset (what you would see on a clock on the wall)</li>
544      * </ul>
545      */
546     public static class TimeDefinition {
547         /** The local date-time is expressed _in terms of the UTC offset. */
548         // static TimeDefinition UTC;
549         // /** The local date-time is expressed _in terms of the wall offset. */
550         // static TimeDefinition WALL;
551         // /** The local date-time is expressed _in terms of the standard offset. */
552         // static TimeDefinition STANDARD;
553 
554         /**
555          * Converts the specified local date-time to the local date-time actually
556          * seen on a wall clock.
557          * !(p)
558          * This method converts using the type of this enum.
559          * The output is defined relative to the 'before' offset of the transition.
560          * !(p)
561          * The UTC type uses the UTC offset.
562          * The STANDARD type uses the standard offset.
563          * The WALL type returns the input date-time.
564          * The result is intended for use with the wall-offset.
565          *
566          * @param dateTime  the local date-time, not null
567          * @param standardOffset  the standard offset, not null
568          * @param wallOffset  the wall offset, not null
569          * @return the date-time relative to the wall/before offset, not null
570          */
571         private int _ordinal;
572         private string _name;
573         static TimeDefinition[] _values;
574 
575         // static this(){
576             // UTC = new TimeDefinition(0,"UTC");
577             mixin(MakeGlobalVar!(TimeDefinition)("UTC",`new TimeDefinition(0,"UTC")`));
578             // WALL = new TimeDefinition(1,"WALL");
579             mixin(MakeGlobalVar!(TimeDefinition)("WALL",`new TimeDefinition(1,"WALL")`));
580 
581             // STANDARD = new TimeDefinition(2,"STANDARD");
582             mixin(MakeGlobalVar!(TimeDefinition)("STANDARD",`new TimeDefinition(2,"STANDARD")`));
583 
584            
585         // }
586 
587         static ref  TimeDefinition[] values()
588         {
589             if(_values.length == 0)
590             {
591                  _values ~= UTC;
592                 _values ~= WALL;
593                 _values ~= STANDARD;
594             }
595             return _values;
596         }
597 
598         public int ordinal()
599         {
600             return _ordinal;
601         }
602         public string name()
603         {
604             return _name;
605         }
606         this(int ordinal , string name)
607         {
608             _ordinal = ordinal;
609             _name = name;
610         }
611         public LocalDateTime createDateTime(LocalDateTime dateTime, ZoneOffset standardOffset, ZoneOffset wallOffset) {
612             auto name = this.name();
613             switch (name) {
614                 case "UTC": {
615                     int difference = wallOffset.getTotalSeconds() - ZoneOffset.UTC.getTotalSeconds();
616                     return dateTime.plusSeconds(difference);
617                 }
618                 case "STANDARD": {
619                     int difference = wallOffset.getTotalSeconds() - standardOffset.getTotalSeconds();
620                     return dateTime.plusSeconds(difference);
621                 }
622                 default:  // WALL
623                     return dateTime;
624             }
625         }
626     }
627 
628     // mixin SerializationMember!(typeof(this));
629 
630 }