/*
D言語 2012/1/20
D言語の機能、mixinとタプルについて。
1. ミックスイン
mixin(string src);
とすることで、srcをソースコードに含めることができる。
Example: */ /+
import std.stdio;
void main(){
mixin("int a = 123");
wirteln(a); //123と表示
}
+/ /*
2. テンプレート・ミックスイン
mixin template Name
と書かれたテンプレートを
mixin Name
とすることで、そのソースコードにNameの中身を含めることができる。
スコープはそこに入る。
Example: */ /+
import std.stdio;
mixin template hogehogehoge(){
string a = "Hello D World";
}
void main(){
mixin hogehogehoge;
writeln(a); //"Hello D World"と表示
}
+/ /*
3. タプル
タプルとは、Haskellなどに実装されている機能で、D言語にも存在する。
タプルの幾つかの機能は言語組み込みで、その他の機能はstd.typeconsやstd.typetupleが提供している。
タプルには次の三種類がある。
1.型タプル
型タプルは */ /+
Tuple!(int,long,real)
+/ /* というように宣言され、要素に型をもつものである。
2.式タプル
式タプルは */ /+
Tuple!("hello","world",1,2,3,4,5)
+/ /* というように宣言されたものである。
3.値タプル
*/ /+ Tuple!(fuga,hoge,hoge) foo; +/ /*
というようにタプル型で宣言された変数fooを値タプルという。
値タプルはC言語の構造体のようなもので、fuga型の値とhoge型とhoge型の値を格納できる。
しかしC言語の構造体と違うのは配列同様にアクセスでき、スライスできることである。
式タプルとの違いは、式タプルは値はstaticでコンパイル時に決定されるが、値タプルは変数であるので実行時に変更が可能な点である。
※型タプルと式タプルは混合することができる。
型タプルと式タプルはテンプレートの可変長個引数 */ /+
template Tuple(E...){
alias E Tuple;
} +/ /*
のE...の部分で作られる。
たとえば *//+
Tuple!(int,"hello",long,"world") +/ /*
とすれば、E[0]はint、E[1]は"hello"、E[2]はlong、E[3]は"world"のように格納される。
さらにタプルは結合やスライスが言語組み込みの機能として動く。
たとえば */ /+
Tuple!(Tuple!(int,int),Tuple!(long,long))[0..3] +/ /*
は、 */ /+
Tuple!(int,int,long) +/ /*
に等しい。
さらにタプルはforeach文でループを回すことができる。(for文では回せない)
タプルがあることにより、D言語のテンプレートは可変長個引数を取れ、さらにスライスとインデックス演算子により再帰的なテンプレート宣言を可能としている。
通常はstd.typeconsやstd.typetupleをインポートしてしまえばtemplate Tupleは宣言せずに使えるが、今回はインポートせずあえてtemplate Tuple(E...)を定義した。
以上3つの機能を使うことによりC++言語では到底かなわないようなテンプレートメタプログラミングが可能である。
今回はベクトルチックな構造体をテンプレートメタプログラミングで作成してみたい。
*/
import std.stdio;
///タプルの作成
template Tuple(E...){
alias E Tuple;
}
///構造体内部の値の作成
template valuecreate(int N,string label,E...){
static if(E.length > 1) //再帰的に処理する。
immutable valuecreate = E[0].stringof ~ " " ~ label ~ N.stringof ~ ";" ~ valuecreate!(N+1,label,E[1..$]);
else static if(E.length == 1)
immutable valuecreate = E[0].stringof ~ " " ~ label ~ N.stringof ~ ";";
else
static assert(0);
}
///構造体を作成
mixin template StructCreate(string label,string valuelabel,E...){
mixin("struct "~label~"{public:"~valuecreate!(0,valuelabel,E)~"\n"~GenerateOpBinary!(label,valuelabel,E.length-1)~"\nalias Tuple!"~E.stringof~" tuple;"~"}");
}
///二項演算子を作りあげる
template GenerateOpBinary(string label,string valuelabel,int N){
immutable GenerateOpBinary = label~" opBinary(string s)("~label~" src){\n"~
label~" dst;\n"
~GenerateOpBinary_Sub!(valuelabel,N)~
"return dst;\n}\n";
}
///二項演算子の中身を作りあげる。
template GenerateOpBinary_Sub(string valuelabel,int N){
static if(N > 0)
immutable GenerateOpBinary_Sub = "mixin(\" dst."~valuelabel~N.stringof~"="~valuelabel~N.stringof~"\"~s~\" src."
~valuelabel~N.stringof~";\");\n"~GenerateOpBinary_Sub!(valuelabel,N-1);
else static if(N == 0)
immutable GenerateOpBinary_Sub = "mixin(\"dst."~valuelabel~N.stringof~"="~valuelabel~N.stringof~"\"~s~\" src."
~valuelabel~N.stringof~";\");\n";
else
static assert(0);
}
void main(){
mixin("int a = 512;"); //文字列mixin
writeln(a);
//構造体hogeはint,real,longをそれぞれval_0,val_1,val_2というメンバーとして持ち、二項演算子が定義された構造体
mixin StructCreate!("hoge","val_",int,real,long);
hoge bar1,bar2,bar3;
bar1.val_0 = 8;
bar1.val_1 = 11;
bar1.val_2 = 12;
bar2.val_0 = 12;
bar2.val_1 = 19;
bar2.val_2 = 28;
writeln(bar1+bar2); //ベクトル和(数学と同じ)
writeln(bar1-bar2); //ベクトル差(数学と同じ)
writeln(bar1*bar2); //プログラムでいうベクトル積(数学とは違う)
writeln(bar1%bar2); //プログラムでいうベクトル剰余演算(数学とは違う)
//浮動小数点数と虚数と複素数とhogeをもつ4(6)次元ベクトルを作成。
mixin StructCreate!("fuga","val_",real,ireal,creal,hoge);
fuga foo1,foo2;
foo1.val_0 = 12.3;
foo1.val_1 = 12.3i;
foo1.val_2 = 12.3 + 12.3i;
foo1.val_3.val_0 = 12;
foo1.val_3.val_1 = 19;
foo1.val_3.val_2 = 120;
foo2 = foo1;
writeln(foo1+foo2);
//9次元ベクトルを作成。 fuga.tupleとhoge.tupleは構造体内部の型のタプルを返すように定義している。
mixin StructCreate!("DDDreland","val_",fuga.tuple,hoge.tuple);
DDDreland Dr1,Dr2;
Dr1.val_0 = 12.3;
Dr1.val_1 = 12.3i;
Dr1.val_2 = 12.3 + 12.3i;
Dr1.val_3.val_0 = 12;
Dr1.val_3.val_1 = 19;
Dr1.val_3.val_2 = 120;
Dr1.val_4 = 8;
Dr1.val_5 = 11;
Dr1.val_6 = 12;
Dr2 = Dr1;
writeln(Dr2+Dr1);
}
LyoKROiogOiqnuOAgDIwMTIvMS8yMApE6KiA6Kqe44Gu5qmf6IO944CBbWl4aW7jgajjgr/jg5fjg6vjgavjgaTjgYTjgabjgIIKCjEu44CA44Of44OD44Kv44K544Kk44OzCm1peGluKHN0cmluZyBzcmMpOwrjgajjgZnjgovjgZPjgajjgafjgIFzcmPjgpLjgr3jg7zjgrnjgrPjg7zjg4njgavlkKvjgoHjgovjgZPjgajjgYzjgafjgY3jgovjgIIKCglFeGFtcGxlOgkqLyAvKwoJaW1wb3J0IHN0ZC5zdGRpbzsKCXZvaWQgbWFpbigpewoJCW1peGluKCJpbnQgYSA9IDEyMyIpOwoJCXdpcnRlbG4oYSk7CQkvLzEyM+OBqOihqOekugoJfQorLyAvKgoKMi7jgIDjg4bjg7Pjg5fjg6zjg7zjg4jjg7vjg5/jg4Pjgq/jgrnjgqTjg7MKbWl4aW4gdGVtcGxhdGUgTmFtZQrjgajmm7jjgYvjgozjgZ/jg4bjg7Pjg5fjg6zjg7zjg4jjgpIKbWl4aW4gTmFtZQrjgajjgZnjgovjgZPjgajjgafjgIHjgZ3jga7jgr3jg7zjgrnjgrPjg7zjg4njgatOYW1l44Gu5Lit6Lqr44KS5ZCr44KB44KL44GT44Go44GM44Gn44GN44KL44CCCuOCueOCs+ODvOODl+OBr+OBneOBk+OBq+WFpeOCi+OAggoKCUV4YW1wbGU6CSovIC8rCglpbXBvcnQgc3RkLnN0ZGlvOwoJbWl4aW4gdGVtcGxhdGUgaG9nZWhvZ2Vob2dlKCl7CgkJc3RyaW5nIGEgPSAiSGVsbG8gRCBXb3JsZCI7Cgl9Cgl2b2lkIG1haW4oKXsKCQltaXhpbiBob2dlaG9nZWhvZ2U7CgkJd3JpdGVsbihhKTsJLy8iSGVsbG8gRCBXb3JsZCLjgajooajnpLoKCX0KKy8gLyoKCjMu44CA44K/44OX44OrCuOCv+ODl+ODq+OBqOOBr+OAgUhhc2tlbGzjgarjganjgavlrp/oo4XjgZXjgozjgabjgYTjgovmqZ/og73jgafjgIFE6KiA6Kqe44Gr44KC5a2Y5Zyo44GZ44KL44CCCuOCv+ODl+ODq+OBruW5vuOBpOOBi+OBruapn+iDveOBr+iogOiqnue1hOOBv+i+vOOBv+OBp+OAgeOBneOBruS7luOBruapn+iDveOBr3N0ZC50eXBlY29uc+OChHN0ZC50eXBldHVwbGXjgYzmj5DkvpvjgZfjgabjgYTjgovjgIIK44K/44OX44Or44Gr44Gv5qyh44Gu5LiJ56iu6aGe44GM44GC44KL44CCCgkxLuWei+OCv+ODl+ODqwoJCeWei+OCv+ODl+ODq+OBrwkqLyAvKwoJCVR1cGxlIShpbnQsbG9uZyxyZWFsKQorLyAvKgnjgajjgYTjgYbjgojjgYbjgavlrqPoqIDjgZXjgozjgIHopoHntKDjgavlnovjgpLjgoLjgaTjgoLjga7jgafjgYLjgovjgIIKCQkKCTIu5byP44K/44OX44OrCgkJ5byP44K/44OX44Or44GvCSovIC8rCgkJVHVwbGUhKCJoZWxsbyIsIndvcmxkIiwxLDIsMyw0LDUpCisvIC8qCeOBqOOBhOOBhuOCiOOBhuOBq+Wuo+iogOOBleOCjOOBn+OCguOBruOBp+OBguOCi+OAggoJCQoJMy7lgKTjgr/jg5fjg6sKKi8gLysJVHVwbGUhKGZ1Z2EsaG9nZSxob2dlKSBmb287CSsvIC8qCgkJ44Go44GE44GG44KI44GG44Gr44K/44OX44Or5Z6L44Gn5a6j6KiA44GV44KM44Gf5aSJ5pWwZm9v44KS5YCk44K/44OX44Or44Go44GE44GG44CCCgkJ5YCk44K/44OX44Or44GvQ+iogOiqnuOBruani+mAoOS9k+OBruOCiOOBhuOBquOCguOBruOBp+OAgWZ1Z2Hlnovjga7lgKTjgahob2dl5Z6L44GoaG9nZeWei+OBruWApOOCkuagvOe0jeOBp+OBjeOCi+OAggoJCeOBl+OBi+OBl0PoqIDoqp7jga7mp4vpgKDkvZPjgajpgZXjgYbjga7jga/phY3liJflkIzmp5jjgavjgqLjgq/jgrvjgrnjgafjgY3jgIHjgrnjg6njgqTjgrnjgafjgY3jgovjgZPjgajjgafjgYLjgovjgIIKCQnlvI/jgr/jg5fjg6vjgajjga7pgZXjgYTjga/jgIHlvI/jgr/jg5fjg6vjga/lgKTjga9zdGF0aWPjgafjgrPjg7Pjg5HjgqTjg6vmmYLjgavmsbrlrprjgZXjgozjgovjgYzjgIHlgKTjgr/jg5fjg6vjga/lpInmlbDjgafjgYLjgovjga7jgaflrp/ooYzmmYLjgavlpInmm7TjgYzlj6/og73jgarngrnjgafjgYLjgovjgIIKCQoJ4oC75Z6L44K/44OX44Or44Go5byP44K/44OX44Or44Gv5re35ZCI44GZ44KL44GT44Go44GM44Gn44GN44KL44CCCgkJCuWei+OCv+ODl+ODq+OBqOW8j+OCv+ODl+ODq+OBr+ODhuODs+ODl+ODrOODvOODiOOBruWPr+WkiemVt+WAi+W8leaVsAkqLyAvKwp0ZW1wbGF0ZSBUdXBsZShFLi4uKXsKCWFsaWFzIEUgVHVwbGU7Cn0JKy8gLyoK44GuRS4uLuOBrumDqOWIhuOBp+S9nOOCieOCjOOCi+OAggrjgZ/jgajjgYjjgbAJKi8vKwpUdXBsZSEoaW50LCJoZWxsbyIsbG9uZywid29ybGQiKQkJKy8gLyoK44Go44GZ44KM44Gw44CBRVswXeOBr2ludOOAgUVbMV3jga8iaGVsbG8i44CBRVsyXeOBr2xvbmfjgIFFWzNd44GvIndvcmxkIuOBruOCiOOBhuOBq+agvOe0jeOBleOCjOOCi+OAggrjgZXjgonjgavjgr/jg5fjg6vjga/ntZDlkIjjgoTjgrnjg6njgqTjgrnjgYzoqIDoqp7ntYTjgb/ovrzjgb/jga7mqZ/og73jgajjgZfjgabli5XjgY/jgIIK44Gf44Go44GI44GwCQkqLyAvKwpUdXBsZSEoVHVwbGUhKGludCxpbnQpLFR1cGxlIShsb25nLGxvbmcpKVswLi4zXQkrLyAvKgrjga/jgIEJCSovIC8rClR1cGxlIShpbnQsaW50LGxvbmcpCSsvIC8qCuOBq+etieOBl+OBhOOAggrjgZXjgonjgavjgr/jg5fjg6vjga9mb3JlYWNo5paH44Gn44Or44O844OX44KS5Zue44GZ44GT44Go44GM44Gn44GN44KL44CCKGZvcuaWh+OBp+OBr+WbnuOBm+OBquOBhCkK44K/44OX44Or44GM44GC44KL44GT44Go44Gr44KI44KK44CBROiogOiqnuOBruODhuODs+ODl+ODrOODvOODiOOBr+WPr+WkiemVt+WAi+W8leaVsOOCkuWPluOCjOOAgeOBleOCieOBq+OCueODqeOCpOOCueOBqOOCpOODs+ODh+ODg+OCr+OCuea8lOeul+WtkOOBq+OCiOOCiuWGjeW4sOeahOOBquODhuODs+ODl+ODrOODvOODiOWuo+iogOOCkuWPr+iDveOBqOOBl+OBpuOBhOOCi+OAggrpgJrluLjjga9zdGQudHlwZWNvbnPjgoRzdGQudHlwZXR1cGxl44KS44Kk44Oz44Od44O844OI44GX44Gm44GX44G+44GI44GwdGVtcGxhdGUgVHVwbGXjga/lrqPoqIDjgZvjgZrjgavkvb/jgYjjgovjgYzjgIHku4rlm57jga/jgqTjg7Pjg53jg7zjg4jjgZvjgZrjgYLjgYjjgaZ0ZW1wbGF0ZSBUdXBsZShFLi4uKeOCkuWumue+qeOBl+OBn+OAggoK5Lul5LiKM+OBpOOBruapn+iDveOCkuS9v+OBhuOBk+OBqOOBq+OCiOOCikMrK+iogOiqnuOBp+OBr+WIsOW6leOBi+OBquOCj+OBquOBhOOCiOOBhuOBquODhuODs+ODl+ODrOODvOODiOODoeOCv+ODl+ODreOCsOODqeODn+ODs+OCsOOBjOWPr+iDveOBp+OBguOCi+OAggrku4rlm57jga/jg5njgq/jg4jjg6vjg4Hjg4Pjgq/jgarmp4vpgKDkvZPjgpLjg4bjg7Pjg5fjg6zjg7zjg4jjg6Hjgr/jg5fjg63jgrDjg6njg5/jg7PjgrDjgafkvZzmiJDjgZfjgabjgb/jgZ/jgYTjgIIKKi8KCmltcG9ydCBzdGQuc3RkaW87CgovLy/jgr/jg5fjg6vjga7kvZzmiJAKdGVtcGxhdGUgVHVwbGUoRS4uLil7CglhbGlhcyBFIFR1cGxlOwp9CgovLy/mp4vpgKDkvZPlhoXpg6jjga7lgKTjga7kvZzmiJAKdGVtcGxhdGUgdmFsdWVjcmVhdGUoaW50IE4sc3RyaW5nIGxhYmVsLEUuLi4pewoJc3RhdGljIGlmKEUubGVuZ3RoID4gMSkJCS8v5YaN5biw55qE44Gr5Yem55CG44GZ44KL44CCCgkJaW1tdXRhYmxlIHZhbHVlY3JlYXRlID0gRVswXS5zdHJpbmdvZiB+ICIgIiB+IGxhYmVsIH4gTi5zdHJpbmdvZiB+ICI7IiB+IHZhbHVlY3JlYXRlIShOKzEsbGFiZWwsRVsxLi4kXSk7CgllbHNlIHN0YXRpYyBpZihFLmxlbmd0aCA9PSAxKQoJCWltbXV0YWJsZSB2YWx1ZWNyZWF0ZSA9IEVbMF0uc3RyaW5nb2YgfiAiICIgfiBsYWJlbCB+IE4uc3RyaW5nb2YgfiAiOyI7CgllbHNlCgkJc3RhdGljIGFzc2VydCgwKTsKfQoKLy8v5qeL6YCg5L2T44KS5L2c5oiQCm1peGluIHRlbXBsYXRlIFN0cnVjdENyZWF0ZShzdHJpbmcgbGFiZWwsc3RyaW5nIHZhbHVlbGFiZWwsRS4uLil7CgltaXhpbigic3RydWN0ICJ+bGFiZWx+IntwdWJsaWM6In52YWx1ZWNyZWF0ZSEoMCx2YWx1ZWxhYmVsLEUpfiJcbiJ+R2VuZXJhdGVPcEJpbmFyeSEobGFiZWwsdmFsdWVsYWJlbCxFLmxlbmd0aC0xKX4iXG5hbGlhcyBUdXBsZSEifkUuc3RyaW5nb2Z+IiB0dXBsZTsifiJ9Iik7Cn0KCi8vL+S6jOmghea8lOeul+WtkOOCkuS9nOOCiuOBguOBkuOCiwp0ZW1wbGF0ZSBHZW5lcmF0ZU9wQmluYXJ5KHN0cmluZyBsYWJlbCxzdHJpbmcgdmFsdWVsYWJlbCxpbnQgTil7CglpbW11dGFibGUgR2VuZXJhdGVPcEJpbmFyeSA9IGxhYmVsfiIgb3BCaW5hcnkoc3RyaW5nIHMpKCJ+bGFiZWx+IiBzcmMpe1xuIn4KCQkJCQkJCQkJCWxhYmVsfiIgZHN0O1xuIgoJCQkJCQkJCQkJfkdlbmVyYXRlT3BCaW5hcnlfU3ViISh2YWx1ZWxhYmVsLE4pfgoJCQkJCQkJCQkJInJldHVybiBkc3Q7XG59XG4iOwkJCQkJCQp9CgovLy/kuozpoIXmvJTnrpflrZDjga7kuK3ouqvjgpLkvZzjgorjgYLjgZLjgovjgIIKdGVtcGxhdGUgR2VuZXJhdGVPcEJpbmFyeV9TdWIoc3RyaW5nIHZhbHVlbGFiZWwsaW50IE4pewoJc3RhdGljIGlmKE4gPiAwKQoJCWltbXV0YWJsZSBHZW5lcmF0ZU9wQmluYXJ5X1N1YiA9ICJtaXhpbihcIiBkc3QuIn52YWx1ZWxhYmVsfk4uc3RyaW5nb2Z+Ij0ifnZhbHVlbGFiZWx+Ti5zdHJpbmdvZn4iXCJ+c35cIiBzcmMuIgoJCQkJCQkJCQkJfnZhbHVlbGFiZWx+Ti5zdHJpbmdvZn4iO1wiKTtcbiJ+R2VuZXJhdGVPcEJpbmFyeV9TdWIhKHZhbHVlbGFiZWwsTi0xKTsKCWVsc2Ugc3RhdGljIGlmKE4gPT0gMCkKCQlpbW11dGFibGUgR2VuZXJhdGVPcEJpbmFyeV9TdWIgPSAibWl4aW4oXCJkc3QuIn52YWx1ZWxhYmVsfk4uc3RyaW5nb2Z+Ij0ifnZhbHVlbGFiZWx+Ti5zdHJpbmdvZn4iXCJ+c35cIiBzcmMuIgoJCQkJCQkJCQkJfnZhbHVlbGFiZWx+Ti5zdHJpbmdvZn4iO1wiKTtcbiI7CgllbHNlCgkJc3RhdGljIGFzc2VydCgwKTsKfQoKdm9pZCBtYWluKCl7CgltaXhpbigiaW50IGEgPSA1MTI7Iik7CS8v5paH5a2X5YiXbWl4aW4KCXdyaXRlbG4oYSk7CgkKCS8v5qeL6YCg5L2TaG9nZeOBr2ludCxyZWFsLGxvbmfjgpLjgZ3jgozjgZ7jgox2YWxfMCx2YWxfMSx2YWxfMuOBqOOBhOOBhuODoeODs+ODkOODvOOBqOOBl+OBpuaMgeOBoeOAgeS6jOmghea8lOeul+WtkOOBjOWumue+qeOBleOCjOOBn+ani+mAoOS9kwoJbWl4aW4gU3RydWN0Q3JlYXRlISgiaG9nZSIsInZhbF8iLGludCxyZWFsLGxvbmcpOwoJCglob2dlIGJhcjEsYmFyMixiYXIzOwoJCgliYXIxLnZhbF8wID0gODsKCWJhcjEudmFsXzEgPSAxMTsKCWJhcjEudmFsXzIgPSAxMjsKCQoJYmFyMi52YWxfMCA9IDEyOwoJYmFyMi52YWxfMSA9IDE5OwoJYmFyMi52YWxfMiA9IDI4OwoJCgl3cml0ZWxuKGJhcjErYmFyMik7CQkJLy/jg5njgq/jg4jjg6vlkowo5pWw5a2m44Go5ZCM44GYKQkKCXdyaXRlbG4oYmFyMS1iYXIyKTsJCQkvL+ODmeOCr+ODiOODq+W3rijmlbDlrabjgajlkIzjgZgpCQoJd3JpdGVsbihiYXIxKmJhcjIpOwkJCS8v44OX44Ot44Kw44Op44Og44Gn44GE44GG44OZ44Kv44OI44Or56mNKOaVsOWtpuOBqOOBr+mBleOBhikJCgl3cml0ZWxuKGJhcjElYmFyMik7CQkJLy/jg5fjg63jgrDjg6njg6DjgafjgYTjgYbjg5njgq/jg4jjg6vlibDkvZnmvJTnrpco5pWw5a2m44Go44Gv6YGV44GGKQoJCgkvL+a1ruWLleWwj+aVsOeCueaVsOOBqOiZmuaVsOOBqOikh+e0oOaVsOOBqGhvZ2XjgpLjgoLjgaQ0KDYp5qyh5YWD44OZ44Kv44OI44Or44KS5L2c5oiQ44CCCgltaXhpbiBTdHJ1Y3RDcmVhdGUhKCJmdWdhIiwidmFsXyIscmVhbCxpcmVhbCxjcmVhbCxob2dlKTsKCQoJZnVnYSBmb28xLGZvbzI7Cglmb28xLnZhbF8wID0gMTIuMzsKCWZvbzEudmFsXzEgPSAxMi4zaTsKCWZvbzEudmFsXzIgPSAxMi4zICsgMTIuM2k7Cglmb28xLnZhbF8zLnZhbF8wID0gMTI7Cglmb28xLnZhbF8zLnZhbF8xID0gMTk7Cglmb28xLnZhbF8zLnZhbF8yID0gMTIwOwoJCglmb28yID0gZm9vMTsKCXdyaXRlbG4oZm9vMStmb28yKTsKCQoJLy855qyh5YWD44OZ44Kv44OI44Or44KS5L2c5oiQ44CCIGZ1Z2EudHVwbGXjgahob2dlLnR1cGxl44Gv5qeL6YCg5L2T5YaF6YOo44Gu5Z6L44Gu44K/44OX44Or44KS6L+U44GZ44KI44GG44Gr5a6a576p44GX44Gm44GE44KL44CCCgltaXhpbiBTdHJ1Y3RDcmVhdGUhKCJERERyZWxhbmQiLCJ2YWxfIixmdWdhLnR1cGxlLGhvZ2UudHVwbGUpOwoJREREcmVsYW5kIERyMSxEcjI7CglEcjEudmFsXzAgPSAxMi4zOwoJRHIxLnZhbF8xID0gMTIuM2k7CglEcjEudmFsXzIgPSAxMi4zICsgMTIuM2k7CglEcjEudmFsXzMudmFsXzAgPSAxMjsKCURyMS52YWxfMy52YWxfMSA9IDE5OwoJRHIxLnZhbF8zLnZhbF8yID0gMTIwOwoJRHIxLnZhbF80ID0gODsKCURyMS52YWxfNSA9IDExOwoJRHIxLnZhbF82ID0gMTI7CgkKCURyMiA9IERyMTsKCXdyaXRlbG4oRHIyK0RyMSk7Cn0=