diff options
Diffstat (limited to 'OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs')
-rw-r--r-- | OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs | 274 |
1 files changed, 158 insertions, 116 deletions
diff --git a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs index fcb98a5..0ca5ff3 100644 --- a/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs +++ b/OpenSim/Region/ScriptEngine/Shared/LSL_Types.cs | |||
@@ -102,19 +102,19 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
102 | 102 | ||
103 | public override string ToString() | 103 | public override string ToString() |
104 | { | 104 | { |
105 | string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", x, y, z); | 105 | string s=String.Format(Culture.FormatProvider,"<{0:0.000000},{1:0.000000},{2:0.000000}>", x, y, z); |
106 | return s; | 106 | return s; |
107 | } | 107 | } |
108 | 108 | ||
109 | public static explicit operator LSLString(Vector3 vec) | 109 | public static explicit operator LSLString(Vector3 vec) |
110 | { | 110 | { |
111 | string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z); | 111 | string s=String.Format(Culture.FormatProvider,"<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z); |
112 | return new LSLString(s); | 112 | return new LSLString(s); |
113 | } | 113 | } |
114 | 114 | ||
115 | public static explicit operator string(Vector3 vec) | 115 | public static explicit operator string(Vector3 vec) |
116 | { | 116 | { |
117 | string s=String.Format("<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z); | 117 | string s=String.Format(Culture.FormatProvider,"<{0:0.000000},{1:0.000000},{2:0.000000}>", vec.x, vec.y, vec.z); |
118 | return s; | 118 | return s; |
119 | } | 119 | } |
120 | 120 | ||
@@ -371,6 +371,31 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
371 | 371 | ||
372 | #endregion | 372 | #endregion |
373 | 373 | ||
374 | #region Methods | ||
375 | public Quaternion Normalize() | ||
376 | { | ||
377 | double length = Math.Sqrt(x * x + y * y + z * z + s * s); | ||
378 | if (length < float.Epsilon) | ||
379 | { | ||
380 | x = 0; | ||
381 | y = 0; | ||
382 | z = 0; | ||
383 | s = 1; | ||
384 | } | ||
385 | else | ||
386 | { | ||
387 | |||
388 | double invLength = 1.0 / length; | ||
389 | x *= invLength; | ||
390 | y *= invLength; | ||
391 | z *= invLength; | ||
392 | s *= invLength; | ||
393 | } | ||
394 | |||
395 | return this; | ||
396 | } | ||
397 | #endregion | ||
398 | |||
374 | #region Overriders | 399 | #region Overriders |
375 | 400 | ||
376 | public override int GetHashCode() | 401 | public override int GetHashCode() |
@@ -477,7 +502,7 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
477 | } | 502 | } |
478 | 503 | ||
479 | [Serializable] | 504 | [Serializable] |
480 | public class list | 505 | public struct list |
481 | { | 506 | { |
482 | private object[] m_data; | 507 | private object[] m_data; |
483 | 508 | ||
@@ -544,111 +569,136 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
544 | 569 | ||
545 | set {m_data = value; } | 570 | set {m_data = value; } |
546 | } | 571 | } |
547 | // Function to obtain LSL type from an index. This is needed | 572 | |
548 | // because LSL lists allow for multiple types, and safely | 573 | /// <summary> |
549 | // iterating in them requires a type check. | 574 | /// Obtain LSL type from an index. |
575 | /// </summary> | ||
576 | /// <remarks> | ||
577 | /// This is needed because LSL lists allow for multiple types, and safely | ||
578 | /// iterating in them requires a type check. | ||
579 | /// </remarks> | ||
580 | /// <returns></returns> | ||
581 | /// <param name='itemIndex'></param> | ||
550 | public Type GetLSLListItemType(int itemIndex) | 582 | public Type GetLSLListItemType(int itemIndex) |
551 | { | 583 | { |
552 | return m_data[itemIndex].GetType(); | 584 | return Data[itemIndex].GetType(); |
553 | } | 585 | } |
554 | 586 | ||
555 | // Member functions to obtain item as specific types. | 587 | /// <summary> |
556 | // For cases where implicit conversions would apply if items | 588 | /// Obtain float from an index. |
557 | // were not in a list (e.g. integer to float, but not float | 589 | /// </summary> |
558 | // to integer) functions check for alternate types so as to | 590 | /// <remarks> |
559 | // down-cast from Object to the correct type. | 591 | /// For cases where implicit conversions would apply if items |
560 | // Note: no checks for item index being valid are performed | 592 | /// were not in a list (e.g. integer to float, but not float |
561 | 593 | /// to integer) functions check for alternate types so as to | |
594 | /// down-cast from Object to the correct type. | ||
595 | /// Note: no checks for item index being valid are performed | ||
596 | /// </remarks> | ||
597 | /// <returns></returns> | ||
598 | /// <param name='itemIndex'></param> | ||
562 | public LSL_Types.LSLFloat GetLSLFloatItem(int itemIndex) | 599 | public LSL_Types.LSLFloat GetLSLFloatItem(int itemIndex) |
563 | { | 600 | { |
564 | if (m_data[itemIndex] is LSL_Types.LSLInteger) | 601 | if (Data[itemIndex] is LSL_Types.LSLInteger) |
565 | { | 602 | { |
566 | return (LSL_Types.LSLInteger)m_data[itemIndex]; | 603 | return (LSL_Types.LSLInteger)Data[itemIndex]; |
567 | } | 604 | } |
568 | else if (m_data[itemIndex] is Int32) | 605 | else if (Data[itemIndex] is Int32) |
569 | { | 606 | { |
570 | return new LSL_Types.LSLFloat((int)m_data[itemIndex]); | 607 | return new LSL_Types.LSLFloat((int)Data[itemIndex]); |
571 | } | 608 | } |
572 | else if (m_data[itemIndex] is float) | 609 | else if (Data[itemIndex] is float) |
573 | { | 610 | { |
574 | return new LSL_Types.LSLFloat((float)m_data[itemIndex]); | 611 | return new LSL_Types.LSLFloat((float)Data[itemIndex]); |
575 | } | 612 | } |
576 | else if (m_data[itemIndex] is Double) | 613 | else if (Data[itemIndex] is Double) |
577 | { | 614 | { |
578 | return new LSL_Types.LSLFloat((Double)m_data[itemIndex]); | 615 | return new LSL_Types.LSLFloat((Double)Data[itemIndex]); |
579 | } | 616 | } |
580 | else if (m_data[itemIndex] is LSL_Types.LSLString) | 617 | else if (Data[itemIndex] is LSL_Types.LSLString) |
581 | { | 618 | { |
582 | return new LSL_Types.LSLFloat(m_data[itemIndex].ToString()); | 619 | return new LSL_Types.LSLFloat(Data[itemIndex].ToString()); |
583 | } | 620 | } |
584 | else | 621 | else |
585 | { | 622 | { |
586 | return (LSL_Types.LSLFloat)m_data[itemIndex]; | 623 | return (LSL_Types.LSLFloat)Data[itemIndex]; |
587 | } | 624 | } |
588 | } | 625 | } |
589 | 626 | ||
590 | public LSL_Types.LSLString GetLSLStringItem(int itemIndex) | 627 | public LSL_Types.LSLString GetLSLStringItem(int itemIndex) |
591 | { | 628 | { |
592 | if (m_data[itemIndex] is LSL_Types.key) | 629 | if (Data[itemIndex] is LSL_Types.key) |
593 | { | 630 | { |
594 | return (LSL_Types.key)m_data[itemIndex]; | 631 | return (LSL_Types.key)Data[itemIndex]; |
595 | } | 632 | } |
596 | else if (m_data[itemIndex] is String) | 633 | else |
597 | { | 634 | { |
598 | return new LSL_Types.LSLString((string)m_data[itemIndex]); | 635 | return new LSL_Types.LSLString(Data[itemIndex].ToString()); |
599 | } | 636 | } |
600 | else if (m_data[itemIndex] is LSL_Types.LSLFloat) | ||
601 | { | ||
602 | return new LSL_Types.LSLString((LSLFloat)m_data[itemIndex]); | ||
603 | } | ||
604 | else if (m_data[itemIndex] is LSL_Types.LSLInteger) | ||
605 | { | ||
606 | return new LSL_Types.LSLString((LSLInteger)m_data[itemIndex]); | ||
607 | } | ||
608 | else | ||
609 | { | ||
610 | return (LSL_Types.LSLString)m_data[itemIndex]; | ||
611 | } | ||
612 | } | 637 | } |
613 | 638 | ||
614 | public LSL_Types.LSLInteger GetLSLIntegerItem(int itemIndex) | 639 | public LSL_Types.LSLInteger GetLSLIntegerItem(int itemIndex) |
615 | { | 640 | { |
616 | if (m_data[itemIndex] is LSL_Types.LSLInteger) | 641 | if (Data[itemIndex] is LSL_Types.LSLInteger) |
617 | return (LSL_Types.LSLInteger)m_data[itemIndex]; | 642 | return (LSL_Types.LSLInteger)Data[itemIndex]; |
618 | if (m_data[itemIndex] is LSL_Types.LSLFloat) | 643 | if (Data[itemIndex] is LSL_Types.LSLFloat) |
619 | return new LSLInteger((int)m_data[itemIndex]); | 644 | return new LSLInteger((int)Data[itemIndex]); |
620 | else if (m_data[itemIndex] is Int32) | 645 | else if (Data[itemIndex] is Int32) |
621 | return new LSLInteger((int)m_data[itemIndex]); | 646 | return new LSLInteger((int)Data[itemIndex]); |
622 | else if (m_data[itemIndex] is LSL_Types.LSLString) | 647 | else if (Data[itemIndex] is LSL_Types.LSLString) |
623 | return new LSLInteger(m_data[itemIndex].ToString()); | 648 | return new LSLInteger(Data[itemIndex].ToString()); |
624 | else | 649 | else |
625 | throw new InvalidCastException(string.Format( | 650 | throw new InvalidCastException(string.Format( |
626 | "{0} expected but {1} given", | 651 | "{0} expected but {1} given", |
627 | typeof(LSL_Types.LSLInteger).Name, | 652 | typeof(LSL_Types.LSLInteger).Name, |
628 | m_data[itemIndex] != null ? | 653 | Data[itemIndex] != null ? |
629 | m_data[itemIndex].GetType().Name : "null")); | 654 | Data[itemIndex].GetType().Name : "null")); |
630 | } | 655 | } |
631 | 656 | ||
632 | public LSL_Types.Vector3 GetVector3Item(int itemIndex) | 657 | public LSL_Types.Vector3 GetVector3Item(int itemIndex) |
633 | { | 658 | { |
634 | if(m_data[itemIndex] is LSL_Types.Vector3) | 659 | if (Data[itemIndex] is LSL_Types.Vector3) |
635 | return (LSL_Types.Vector3)m_data[itemIndex]; | 660 | { |
661 | return (LSL_Types.Vector3)Data[itemIndex]; | ||
662 | } | ||
663 | else if(Data[itemIndex] is OpenMetaverse.Vector3) | ||
664 | { | ||
665 | return new LSL_Types.Vector3( | ||
666 | (OpenMetaverse.Vector3)Data[itemIndex]); | ||
667 | } | ||
636 | else | 668 | else |
669 | { | ||
637 | throw new InvalidCastException(string.Format( | 670 | throw new InvalidCastException(string.Format( |
638 | "{0} expected but {1} given", | 671 | "{0} expected but {1} given", |
639 | typeof(LSL_Types.Vector3).Name, | 672 | typeof(LSL_Types.Vector3).Name, |
640 | m_data[itemIndex] != null ? | 673 | Data[itemIndex] != null ? |
641 | m_data[itemIndex].GetType().Name : "null")); | 674 | Data[itemIndex].GetType().Name : "null")); |
675 | } | ||
642 | } | 676 | } |
643 | 677 | ||
644 | public LSL_Types.Quaternion GetQuaternionItem(int itemIndex) | 678 | public LSL_Types.Quaternion GetQuaternionItem(int itemIndex) |
645 | { | 679 | { |
646 | return (LSL_Types.Quaternion)m_data[itemIndex]; | 680 | if (Data[itemIndex] is LSL_Types.Quaternion) |
681 | { | ||
682 | return (LSL_Types.Quaternion)Data[itemIndex]; | ||
683 | } | ||
684 | else if(Data[itemIndex] is OpenMetaverse.Quaternion) | ||
685 | { | ||
686 | return new LSL_Types.Quaternion( | ||
687 | (OpenMetaverse.Quaternion)Data[itemIndex]); | ||
688 | } | ||
689 | else | ||
690 | { | ||
691 | throw new InvalidCastException(string.Format( | ||
692 | "{0} expected but {1} given", | ||
693 | typeof(LSL_Types.Quaternion).Name, | ||
694 | Data[itemIndex] != null ? | ||
695 | Data[itemIndex].GetType().Name : "null")); | ||
696 | } | ||
647 | } | 697 | } |
648 | 698 | ||
649 | public LSL_Types.key GetKeyItem(int itemIndex) | 699 | public LSL_Types.key GetKeyItem(int itemIndex) |
650 | { | 700 | { |
651 | return (LSL_Types.key)m_data[itemIndex]; | 701 | return (LSL_Types.key)Data[itemIndex]; |
652 | } | 702 | } |
653 | 703 | ||
654 | public static list operator +(list a, list b) | 704 | public static list operator +(list a, list b) |
@@ -662,8 +712,11 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
662 | 712 | ||
663 | private void ExtendAndAdd(object o) | 713 | private void ExtendAndAdd(object o) |
664 | { | 714 | { |
665 | Array.Resize(ref m_data, Length + 1); | 715 | object[] tmp; |
666 | m_data.SetValue(o, Length - 1); | 716 | tmp = new object[Data.Length + 1]; |
717 | Data.CopyTo(tmp, 0); | ||
718 | tmp.SetValue(o, tmp.Length - 1); | ||
719 | Data = tmp; | ||
667 | } | 720 | } |
668 | 721 | ||
669 | public static list operator +(list a, LSLString s) | 722 | public static list operator +(list a, LSLString s) |
@@ -711,10 +764,10 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
711 | public void Add(object o) | 764 | public void Add(object o) |
712 | { | 765 | { |
713 | object[] tmp; | 766 | object[] tmp; |
714 | tmp = new object[m_data.Length + 1]; | 767 | tmp = new object[Data.Length + 1]; |
715 | m_data.CopyTo(tmp, 0); | 768 | Data.CopyTo(tmp, 0); |
716 | tmp[m_data.Length] = o; | 769 | tmp[Data.Length] = o; // Since this is tmp.Length - 1 |
717 | m_data = tmp; | 770 | Data = tmp; |
718 | } | 771 | } |
719 | 772 | ||
720 | public bool Contains(object o) | 773 | public bool Contains(object o) |
@@ -741,53 +794,53 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
741 | Object[] ret; | 794 | Object[] ret; |
742 | 795 | ||
743 | if (start < 0) | 796 | if (start < 0) |
744 | start=m_data.Length+start; | 797 | start=Data.Length+start; |
745 | 798 | ||
746 | if (start < 0) | 799 | if (start < 0) |
747 | start=0; | 800 | start=0; |
748 | 801 | ||
749 | if (end < 0) | 802 | if (end < 0) |
750 | end=m_data.Length+end; | 803 | end=Data.Length+end; |
751 | if (end < 0) | 804 | if (end < 0) |
752 | end=0; | 805 | end=0; |
753 | 806 | ||
754 | if (start > end) | 807 | if (start > end) |
755 | { | 808 | { |
756 | if (end >= m_data.Length) | 809 | if (end >= Data.Length) |
757 | return new list(new Object[0]); | 810 | return new list(new Object[0]); |
758 | 811 | ||
759 | if (start >= m_data.Length) | 812 | if (start >= Data.Length) |
760 | start=m_data.Length-1; | 813 | start=Data.Length-1; |
761 | 814 | ||
762 | return GetSublist(end, start); | 815 | return GetSublist(end, start); |
763 | } | 816 | } |
764 | 817 | ||
765 | // start >= 0 && end >= 0 here | 818 | // start >= 0 && end >= 0 here |
766 | if (start >= m_data.Length) | 819 | if (start >= Data.Length) |
767 | { | 820 | { |
768 | ret=new Object[m_data.Length]; | 821 | ret=new Object[Data.Length]; |
769 | Array.Copy(m_data, 0, ret, 0, m_data.Length); | 822 | Array.Copy(Data, 0, ret, 0, Data.Length); |
770 | 823 | ||
771 | return new list(ret); | 824 | return new list(ret); |
772 | } | 825 | } |
773 | 826 | ||
774 | if (end >= m_data.Length) | 827 | if (end >= Data.Length) |
775 | end=m_data.Length-1; | 828 | end=Data.Length-1; |
776 | 829 | ||
777 | // now, this makes the math easier | 830 | // now, this makes the math easier |
778 | int remove=end+1-start; | 831 | int remove=end+1-start; |
779 | 832 | ||
780 | ret=new Object[m_data.Length-remove]; | 833 | ret=new Object[Data.Length-remove]; |
781 | if (ret.Length == 0) | 834 | if (ret.Length == 0) |
782 | return new list(ret); | 835 | return new list(ret); |
783 | 836 | ||
784 | int src; | 837 | int src; |
785 | int dest=0; | 838 | int dest=0; |
786 | 839 | ||
787 | for (src = 0; src < m_data.Length; src++) | 840 | for (src = 0; src < Data.Length; src++) |
788 | { | 841 | { |
789 | if (src < start || src > end) | 842 | if (src < start || src > end) |
790 | ret[dest++]=m_data[src]; | 843 | ret[dest++]=Data[src]; |
791 | } | 844 | } |
792 | 845 | ||
793 | return new list(ret); | 846 | return new list(ret); |
@@ -807,12 +860,12 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
807 | 860 | ||
808 | if (start < 0) | 861 | if (start < 0) |
809 | { | 862 | { |
810 | start = m_data.Length + start; | 863 | start = Data.Length + start; |
811 | } | 864 | } |
812 | 865 | ||
813 | if (end < 0) | 866 | if (end < 0) |
814 | { | 867 | { |
815 | end = m_data.Length + end; | 868 | end = Data.Length + end; |
816 | } | 869 | } |
817 | 870 | ||
818 | // The conventional case is start <= end | 871 | // The conventional case is start <= end |
@@ -826,15 +879,15 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
826 | 879 | ||
827 | // Start sublist beyond length | 880 | // Start sublist beyond length |
828 | // Also deals with start AND end still negative | 881 | // Also deals with start AND end still negative |
829 | if (start >= m_data.Length || end < 0) | 882 | if (start >= Data.Length || end < 0) |
830 | { | 883 | { |
831 | return new list(); | 884 | return new list(); |
832 | } | 885 | } |
833 | 886 | ||
834 | // Sublist extends beyond the end of the supplied list | 887 | // Sublist extends beyond the end of the supplied list |
835 | if (end >= m_data.Length) | 888 | if (end >= Data.Length) |
836 | { | 889 | { |
837 | end = m_data.Length - 1; | 890 | end = Data.Length - 1; |
838 | } | 891 | } |
839 | 892 | ||
840 | // Sublist still starts before the beginning of the list | 893 | // Sublist still starts before the beginning of the list |
@@ -845,7 +898,7 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
845 | 898 | ||
846 | ret = new object[end - start + 1]; | 899 | ret = new object[end - start + 1]; |
847 | 900 | ||
848 | Array.Copy(m_data, start, ret, 0, end - start + 1); | 901 | Array.Copy(Data, start, ret, 0, end - start + 1); |
849 | 902 | ||
850 | return new list(ret); | 903 | return new list(ret); |
851 | 904 | ||
@@ -856,7 +909,7 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
856 | else | 909 | else |
857 | { | 910 | { |
858 | 911 | ||
859 | list result = null; | 912 | list result; |
860 | 913 | ||
861 | // If end is negative, then prefix list is empty | 914 | // If end is negative, then prefix list is empty |
862 | if (end < 0) | 915 | if (end < 0) |
@@ -878,7 +931,7 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
878 | 931 | ||
879 | // If start is outside of list, then just return | 932 | // If start is outside of list, then just return |
880 | // the prefix, whatever it is. | 933 | // the prefix, whatever it is. |
881 | if (start >= m_data.Length) | 934 | if (start >= Data.Length) |
882 | { | 935 | { |
883 | return result; | 936 | return result; |
884 | } | 937 | } |
@@ -1056,11 +1109,11 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
1056 | { | 1109 | { |
1057 | string output; | 1110 | string output; |
1058 | output = String.Empty; | 1111 | output = String.Empty; |
1059 | if (m_data.Length == 0) | 1112 | if (Data.Length == 0) |
1060 | { | 1113 | { |
1061 | return String.Empty; | 1114 | return String.Empty; |
1062 | } | 1115 | } |
1063 | foreach (object o in m_data) | 1116 | foreach (object o in Data) |
1064 | { | 1117 | { |
1065 | output = output + o.ToString(); | 1118 | output = output + o.ToString(); |
1066 | } | 1119 | } |
@@ -1255,12 +1308,12 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
1255 | public string ToPrettyString() | 1308 | public string ToPrettyString() |
1256 | { | 1309 | { |
1257 | string output; | 1310 | string output; |
1258 | if (m_data.Length == 0) | 1311 | if (Data.Length == 0) |
1259 | { | 1312 | { |
1260 | return "[]"; | 1313 | return "[]"; |
1261 | } | 1314 | } |
1262 | output = "["; | 1315 | output = "["; |
1263 | foreach (object o in m_data) | 1316 | foreach (object o in Data) |
1264 | { | 1317 | { |
1265 | if (o is String) | 1318 | if (o is String) |
1266 | { | 1319 | { |
@@ -1327,27 +1380,6 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
1327 | } | 1380 | } |
1328 | } | 1381 | } |
1329 | 1382 | ||
1330 | // | ||
1331 | // BELOW IS WORK IN PROGRESS... IT WILL CHANGE, SO DON'T USE YET! :) | ||
1332 | // | ||
1333 | |||
1334 | public struct StringTest | ||
1335 | { | ||
1336 | // Our own little string | ||
1337 | internal string actualString; | ||
1338 | public static implicit operator bool(StringTest mString) | ||
1339 | { | ||
1340 | if (mString.actualString.Length == 0) | ||
1341 | return true; | ||
1342 | return false; | ||
1343 | } | ||
1344 | public override string ToString() | ||
1345 | { | ||
1346 | return actualString; | ||
1347 | } | ||
1348 | |||
1349 | } | ||
1350 | |||
1351 | [Serializable] | 1383 | [Serializable] |
1352 | public struct key | 1384 | public struct key |
1353 | { | 1385 | { |
@@ -1401,6 +1433,16 @@ namespace OpenSim.Region.ScriptEngine.Shared | |||
1401 | return false; | 1433 | return false; |
1402 | } | 1434 | } |
1403 | } | 1435 | } |
1436 | |||
1437 | public static bool operator true(key k) | ||
1438 | { | ||
1439 | return (Boolean)k; | ||
1440 | } | ||
1441 | |||
1442 | public static bool operator false(key k) | ||
1443 | { | ||
1444 | return !(Boolean)k; | ||
1445 | } | ||
1404 | 1446 | ||
1405 | static public implicit operator key(string s) | 1447 | static public implicit operator key(string s) |
1406 | { | 1448 | { |