:- prompt(_, '').
:- use_module(library(readutil)).
kind
(KC
,var(Z
),K1
) :- first
(Z
:K
,KC
), instantiate
(K
,K1
).kind(KC,F $ G, K2) :- kind(KC,F,K1 -> K2), kind(KC,G,K1).
kind(KC,A -> B,o) :- kind(KC,A,o), kind(KC,B,o).
kind(KC,mu(F), K) :- kind(KC,F,K->K).
type
(KC
,C
,var(X
), T1
) --> { first
(X
:T
,C
) }, inst_type
(KC
,T
,T1
).type(KC,C,lam(X,E), A->B) --> type(KC,[X:mono(A)|C],E,B), [kind(KC,A->B,o)].
type(KC,C,X $ Y, B) --> type(KC,C,X,A->B), type(KC,C,Y,A).
type(KC,C,let(X=E0,E1),T) --> type(KC,C,E0,A), type(KC,[X:poly(C,A)|C],E1,T).
type(KC,C,in(N,E), T) --> type(KC,C,E,T0),
{ unfold_N_ap
(1+N
,T0
,F
,[mu
(F
)|Is]), %%%%% Alts is a pattern lambda. (Alts $ E) is "case E of Alts" in Haskell
type(KC,C, Alts,A->T) --> type_alts(KC,C,Alts,A->T), [kind(KC,A->T,o)].
type(KC,C,mit(X,Alts),mu(F)->T) -->
{ is_list(Alts), gensym(r,R),
KC1
= [R
:mono
(o
)|KC
], C1
= [X
:poly
(C
,var(R
)->T
)|C
] }, type_alts(KC1,C1,Alts,F$var(R)->T).
type(KC,C,mit(X,Is-->T0,Alts),A->T) -->
{ is_list(Alts), gensym(r,R),
foldl_ap
(mu
(F
),Is,A
), foldl_ap
(var(R
),Is,RIs
), KC1 = [R:mono(K)|KC], C1 = [X:poly(C,RIs->T0)|C] },
[kind(KC,F,K->K), kind(KC,A->T,o)], % delayed goals
{ foldl_ap
(F
,[var(R
)|Is],FRIs
) }, type_alts(KC1,C1,Alts,FRIs->T).
type_alts(KC,C,[Alt], A->T) --> type_alt(KC,C,Alt,A->T).
type_alts(KC,C,[Alt,Alt2|Alts],A->T) --> type_alt(KC,C,Alt,A->T),
type_alts(KC,C,[Alt2|Alts],A->T).
type_alt(KC,C,P->E,A->T) --> % assume single depth pattern (C x0 .. xn)
{ P =.. [Ctor|Xs], upper_atom(Ctor),
foldl_ap
(var(Ctor
),Vs
,PE
),% PE=var('Cons')$var(x)$var(xs) when E='Cons'(x,xs) findall(X
:mono
(_
),member
(X
,Xs
),C1
,C
) }, % C1 extends C with bindings for Xs type(KC,C1,PE,A), type(KC,C1,E,T).
% assume upper atoms are tycon or con names and lower ones are var names
unfold_N_ap(0,E, E,[]).
unfold_N_ap(N,E0$E1,E,Es) :-
N
>0, M
is N
-1, unfold_N_ap
(M
,E0
,E
,Es0
), append
(Es0
,[E1
],Es
).
foldl_ap(E, [] , E).
foldl_ap(E0,[E1|Es], E) :- foldl_ap(E0$E1, Es, E).
first(X:T,[X1:T1|_]) :- X = X1, T = T1.
first(X:T,[X1:_|Zs]) :- X\==X1, first(X:T, Zs).
instantiate(mono(T),T).
instantiate
(poly
(C
,T
),T1
) :- copy_term(t
(C
,T
),t
(C
,T1
)).
inst_type(KC,poly(C,T),T2) -->
free_variables(T,Xs), free_variables(T1,Xs1) }, % Xs and Xs1 are same length
samekinds(KC,Xs,Xs1), { T1=T2 }. %% unify T1 T2 later (T2 might not be var)
inst_type(_ ,mono(T),T) --> [].
samekinds(KC,[X|Xs],[Y|Ys]) --> { X\==Y }, [kind(KC,X,K),kind(KC,Y,K)],
samekinds(KC,Xs,Ys).
samekinds(KC,[X|Xs],[X|Ys]) --> [], samekinds(KC,Xs,Ys).
samekinds(_ ,[],[]) --> [].
variablize
(var(X
)) :- gensym
(t
,X
).
main:-
process,
type_and_print(KC,C,E,T) :-
phrase(type(KC,C,E,T),Gs),
(bagof(Ty
, X^Y^member
(kind
(X
,Ty
,Y
),Gs
), Tys
); Tys
=[]), free_variables
(Tys
,Xs
), maplist
(variablize
,Xs
), maplist
(call,Gs
), write("kind ctx instantiated as
: "
), print
(KC
), nl, print
(E
: T
), nl.
process:-
/* your code goes here */
type_and_print
(_
,[],lam
(x
,var(x
)),_
), nl, type_and_print
(_
,[],lam
(x
,lam
(y
,var(y
)$var
(x
))),_
), nl, type_and_print
(_
,[],let
(id
=lam
(x
,var(x
)),var(id
)$var
(id
)),_
), nl, KC0 =
[ 'N':mono(o->o)
, 'L':mono(o->o->o)
, 'B':mono((o->o)->(o->o))
],
C0 =
[ 'Z':poly([] , N$R1)
, 'S':poly([] , R1 -> N$R1)
, 'N':poly([] , L$A2$R2)
, 'C':poly([] , A2->(R2->(L$A2$R2)))
, 'BN':poly([] , B$R3$A3)
, 'BC':poly([] , A3 -> R3$(R3$A3) -> B$R3$A3)
, 'plus':poly([], mu(N) -> mu(N) -> mu(N))
%% , 'undefined':poly([], X1231245424)
],
% data B r a = BN | BC a (r(r a))
% B : (* -> *) -> (* -> *)
% BN: B r a
% BC: a -> r(r a) -> B r a
Zero=in(0,Z), Succ=lam(x,in(0,S$X)),
Nil=in(0,N), Cons=lam(x,lam(xs,in(0,C$X$var(xs)))),
BN
= var('BN'), BC
= var('BC'), BNil=in(1,BN), BCons=lam(x,lam(xs,in(1,BC$X$var(xs)))),
TM_id = lam(x,X),
TM_S = lam(x,lam(y,lam(w,(X$W)$(Y$W)))),
TM_bad = lam(x,X$X),
TM_e1
= let
(id
=TM_id
,var(id
)$var
(id
)), TM_e2 = lam(y,let(x=lam(w,Y),X$X)),
TM_e3a = (C$Zero$Nil),
TM_e3f = ['N'->Zero,'C'(x,xs)->X], %% $ (C$Zero$Nil),
TM_e3 = ['N'->Zero,'C'(x,xs)->X] $ (C$Zero$Nil),
TM_lendumb0 = mit(len,['N'->Zero]),
TM_lendumb = mit(len,['N'->Zero,'C'(x,xs)->Zero]),
TM_len
= mit
(len
,['N'->Zero
,'C'(x
,xs
)->Succ$
(var(len
)$var
(xs
))]), %% length of list example
TM_e4
= let
(length
=TM_len
, Cons$
(var(length
)$
(Cons$Zero$Nil
)) $
(Cons$
(var(length
)$
(Cons$Nil$Nil
)) $ Nil
) ), %% sum of bush example
TM_e5 = mit(bsum, [I]-->((I->mu(N))->mu(N)),
[ 'BN' -> lam(f,Zero)
, 'BC'(x,xs) -> lam(f,
$ lam
(ys
,var(bsum
)$var
(ys
)$var
(f
)) ) )
]),
type_and_print
(KC1
,C1
,lam
(x
,lam
(n
,X$Succ$var
(n
))),_
), nl, !, type_and_print
(KC2
,C2
,TM_e3
,_
), nl, !, type_and_print
(KC3
,C3
,TM_len
,_
), nl, !, type_and_print
(KC4
,C4
,TM_e4
,_
), nl, !, type_and_print
(KC5
,C5
,TM_e5
,_
), nl, !,
%% haven't really shown examples of type constructor polymorphsim or
%% kind polymorphism here but you get the idea what strucutural extensions
%% to HM are needed to support type constructor and kind polymoprhisms.
%% At this level, the examples are complex enough. So downloading it and
%% running it on your local SWI-Prolog may be more pleasant to experiment.
%% You may also want a parser and pretty printer for micronax language.
:- main.
Oi0gc2V0X3Byb2xvZ19mbGFnKHZlcmJvc2Usc2lsZW50KS4KOi0gcHJvbXB0KF8sICcnKS4KOi0gdXNlX21vZHVsZShsaWJyYXJ5KHJlYWR1dGlsKSkuCgo6LSBzZXRfcHJvbG9nX2ZsYWcob2NjdXJzX2NoZWNrLHRydWUpLgo6LSBvcCg1MDAseWZ4LCQpLgoKa2luZChLQyx2YXIoWiksSzEpIDotIGZpcnN0KFo6SyxLQyksIGluc3RhbnRpYXRlKEssSzEpLgpraW5kKEtDLEYgJCBHLCBLMikgOi0ga2luZChLQyxGLEsxIC0+IEsyKSwga2luZChLQyxHLEsxKS4Ka2luZChLQyxBIC0+IEIsbykgIDotIGtpbmQoS0MsQSxvKSwga2luZChLQyxCLG8pLgpraW5kKEtDLG11KEYpLCBLKSAgOi0ga2luZChLQyxGLEstPkspLgoKdHlwZShLQyxDLHZhcihYKSwgICAgIFQxKSAtLT4geyBmaXJzdChYOlQsQykgfSwgaW5zdF90eXBlKEtDLFQsVDEpLgp0eXBlKEtDLEMsbGFtKFgsRSksIEEtPkIpIC0tPiB0eXBlKEtDLFtYOm1vbm8oQSl8Q10sRSxCKSwgW2tpbmQoS0MsQS0+QixvKV0uCnR5cGUoS0MsQyxYICQgWSwgICAgICAgQikgLS0+IHR5cGUoS0MsQyxYLEEtPkIpLCB0eXBlKEtDLEMsWSxBKS4KdHlwZShLQyxDLGxldChYPUUwLEUxKSxUKSAtLT4gdHlwZShLQyxDLEUwLEEpLCB0eXBlKEtDLFtYOnBvbHkoQyxBKXxDXSxFMSxUKS4KdHlwZShLQyxDLGluKE4sRSksICAgICBUKSAtLT4gdHlwZShLQyxDLEUsVDApLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7IHVuZm9sZF9OX2FwKDErTixUMCxGLFttdShGKXxJc10pLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbGRsX2FwKG11KEYpLElzLFQpIH0uCiUlJSUlIEFsdHMgaXMgYSBwYXR0ZXJuIGxhbWJkYS4gKEFsdHMgJCBFKSBpcyAiY2FzZSBFIG9mIEFsdHMiIGluIEhhc2tlbGwKdHlwZShLQyxDLCAgICAgQWx0cyxBLT5UKSAtLT4gdHlwZV9hbHRzKEtDLEMsQWx0cyxBLT5UKSwgW2tpbmQoS0MsQS0+VCxvKV0uCgp0eXBlKEtDLEMsbWl0KFgsQWx0cyksbXUoRiktPlQpIC0tPgogIHsgaXNfbGlzdChBbHRzKSwgZ2Vuc3ltKHIsUiksCiAgICBLQzEgPSBbUjptb25vKG8pfEtDXSwgQzEgPSBbWDpwb2x5KEMsdmFyKFIpLT5UKXxDXSB9LAogIHR5cGVfYWx0cyhLQzEsQzEsQWx0cyxGJHZhcihSKS0+VCkuCgp0eXBlKEtDLEMsbWl0KFgsSXMtLT5UMCxBbHRzKSxBLT5UKSAtLT4KICB7IGlzX2xpc3QoQWx0cyksIGdlbnN5bShyLFIpLAogICAgZm9sZGxfYXAobXUoRiksSXMsQSksIGZvbGRsX2FwKHZhcihSKSxJcyxSSXMpLAogICAgS0MxID0gW1I6bW9ubyhLKXxLQ10sIEMxID0gW1g6cG9seShDLFJJcy0+VDApfENdIH0sCiAgW2tpbmQoS0MsRixLLT5LKSwga2luZChLQyxBLT5ULG8pXSwgJSBkZWxheWVkIGdvYWxzCiAgeyBmb2xkbF9hcChGLFt2YXIoUil8SXNdLEZSSXMpIH0sCiAgdHlwZV9hbHRzKEtDMSxDMSxBbHRzLEZSSXMtPlQpLgoKCnR5cGVfYWx0cyhLQyxDLFtBbHRdLCAgICAgICAgICBBLT5UKSAtLT4gdHlwZV9hbHQoS0MsQyxBbHQsQS0+VCkuCnR5cGVfYWx0cyhLQyxDLFtBbHQsQWx0MnxBbHRzXSxBLT5UKSAtLT4gdHlwZV9hbHQoS0MsQyxBbHQsQS0+VCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZV9hbHRzKEtDLEMsW0FsdDJ8QWx0c10sQS0+VCkuCgp0eXBlX2FsdChLQyxDLFAtPkUsQS0+VCkgLS0+ICUgYXNzdW1lIHNpbmdsZSBkZXB0aCBwYXR0ZXJuIChDIHgwIC4uIHhuKQogIHsgUCA9Li4gW0N0b3J8WHNdLCB1cHBlcl9hdG9tKEN0b3IpLAogICAgZmluZGFsbCh2YXIoWCksbWVtYmVyKFgsWHMpLFZzKSwKICAgIGZvbGRsX2FwKHZhcihDdG9yKSxWcyxQRSksJSBQRT12YXIoJ0NvbnMnKSR2YXIoeCkkdmFyKHhzKSB3aGVuIEU9J0NvbnMnKHgseHMpCiAgICBmaW5kYWxsKFg6bW9ubyhfKSxtZW1iZXIoWCxYcyksQzEsQykgfSwgJSBDMSBleHRlbmRzIEMgd2l0aCBiaW5kaW5ncyBmb3IgWHMKICB0eXBlKEtDLEMxLFBFLEEpLCB0eXBlKEtDLEMxLEUsVCkuCgolIGFzc3VtZSB1cHBlciBhdG9tcyBhcmUgdHljb24gb3IgY29uIG5hbWVzIGFuZCBsb3dlciBvbmVzIGFyZSB2YXIgbmFtZXMKdXBwZXJfYXRvbShBKSA6LSBhdG9tKEEpLCBhdG9tX2NoYXJzKEEsW0N8X10pLCBjaGFyX3R5cGUoQyx1cHBlcikuCmxvd2VyX2F0b20oQSkgOi0gYXRvbShBKSwgYXRvbV9jaGFycyhBLFtDfF9dKSwgY2hhcl90eXBlKEMsbG93ZXIpLgoKdW5mb2xkX05fYXAoMCxFLCAgICBFLFtdKS4KdW5mb2xkX05fYXAoTixFMCRFMSxFLEVzKSA6LQogIE4+MCwgTSBpcyBOLTEsIHVuZm9sZF9OX2FwKE0sRTAsRSxFczApLCBhcHBlbmQoRXMwLFtFMV0sRXMpLgoKZm9sZGxfYXAoRSwgW10gICAgICwgRSkuCmZvbGRsX2FwKEUwLFtFMXxFc10sIEUpIDotIGZvbGRsX2FwKEUwJEUxLCBFcywgRSkuCgoKCmZpcnN0KFg6VCxbWDE6VDF8X10pIDotIFggPSBYMSwgVCA9IFQxLgpmaXJzdChYOlQsW1gxOl98WnNdKSA6LSBYXD09WDEsIGZpcnN0KFg6VCwgWnMpLgoKaW5zdGFudGlhdGUobW9ubyhUKSxUKS4KaW5zdGFudGlhdGUocG9seShDLFQpLFQxKSA6LSBjb3B5X3Rlcm0odChDLFQpLHQoQyxUMSkpLgoKaW5zdF90eXBlKEtDLHBvbHkoQyxUKSxUMikgLS0+CiAgeyBjb3B5X3Rlcm0odChDLFQpLHQoQyxUMSkpLCAKICAgIGZyZWVfdmFyaWFibGVzKFQsWHMpLCBmcmVlX3ZhcmlhYmxlcyhUMSxYczEpIH0sICUgWHMgYW5kIFhzMSBhcmUgc2FtZSBsZW5ndGgKICBzYW1la2luZHMoS0MsWHMsWHMxKSwgeyBUMT1UMiB9LiAlJSB1bmlmeSBUMSBUMiBsYXRlciAoVDIgbWlnaHQgbm90IGJlIHZhcikKaW5zdF90eXBlKF8gLG1vbm8oVCksVCkgLS0+IFtdLgoKc2FtZWtpbmRzKEtDLFtYfFhzXSxbWXxZc10pIC0tPiB7IFhcPT1ZIH0sIFtraW5kKEtDLFgsSyksa2luZChLQyxZLEspXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW1la2luZHMoS0MsWHMsWXMpLgpzYW1la2luZHMoS0MsW1h8WHNdLFtYfFlzXSkgLS0+IFtdLCBzYW1la2luZHMoS0MsWHMsWXMpLgpzYW1la2luZHMoXyAsW10sW10pIC0tPiBbXS4KCnZhcmlhYmxpemUodmFyKFgpKSA6LSBnZW5zeW0odCxYKS4KCm1haW46LQoJcHJvY2VzcywKCWhhbHQuCgp0eXBlX2FuZF9wcmludChLQyxDLEUsVCkgOi0KICBwaHJhc2UodHlwZShLQyxDLEUsVCksR3MpLAogIChiYWdvZihUeSwgWF5ZXm1lbWJlcihraW5kKFgsVHksWSksR3MpLCBUeXMpOyBUeXM9W10pLAogIGZyZWVfdmFyaWFibGVzKFR5cyxYcyksIG1hcGxpc3QodmFyaWFibGl6ZSxYcyksIG1hcGxpc3QoY2FsbCxHcyksCiAgd3JpdGUoImtpbmQgY3R4IGluc3RhbnRpYXRlZCBhczogIiksIHByaW50KEtDKSwgbmwsIHByaW50KEUgOiBUKSwgbmwuCgpwcm9jZXNzOi0KCS8qIHlvdXIgY29kZSBnb2VzIGhlcmUgKi8KCXR5cGVfYW5kX3ByaW50KF8sW10sbGFtKHgsdmFyKHgpKSxfKSwgbmwsCgl0eXBlX2FuZF9wcmludChfLFtdLGxhbSh4LGxhbSh5LHZhcih5KSR2YXIoeCkpKSxfKSwgbmwsCgl0eXBlX2FuZF9wcmludChfLFtdLGxldChpZD1sYW0oeCx2YXIoeCkpLHZhcihpZCkkdmFyKGlkKSksXyksIG5sLAoJS0MwID0KCSBbICdOJzptb25vKG8tPm8pCiAgICAgLCAnTCc6bW9ubyhvLT5vLT5vKQogICAgICwgJ0InOm1vbm8oKG8tPm8pLT4oby0+bykpCiAgICAgXSwKICAgIEMwID0KICAgICBbICdaJzpwb2x5KFtdICwgTiRSMSkKICAgICAsICdTJzpwb2x5KFtdICwgUjEgLT4gTiRSMSkKICAgICAsICdOJzpwb2x5KFtdICwgTCRBMiRSMikKICAgICAsICdDJzpwb2x5KFtdICwgQTItPihSMi0+KEwkQTIkUjIpKSkKICAgICAsICdCTic6cG9seShbXSAsIEIkUjMkQTMpCiAgICAgLCAnQkMnOnBvbHkoW10gLCBBMyAtPiBSMyQoUjMkQTMpIC0+IEIkUjMkQTMpCiAgICAgLCAncGx1cyc6cG9seShbXSwgbXUoTikgLT4gbXUoTikgLT4gbXUoTikpCiAgICAgJSUgLCAndW5kZWZpbmVkJzpwb2x5KFtdLCBYMTIzMTI0NTQyNCkKICAgICBdLAogICAgTiA9IHZhcignTicpLCBMID0gdmFyKCdMJyksIEIgPSB2YXIoJ0InKSwKJSBkYXRhIEIgciBhID0gQk4gfCBCQyBhIChyKHIgYSkpCiUgQiA6ICgqIC0+ICopIC0+ICgqIC0+ICopCiUgQk46IEIgciBhCiUgQkM6IGEgLT4gcihyIGEpIC0+IEIgciBhCiAgICBYID0gdmFyKHgpLCBZID0gdmFyKHkpLCBXID0gdmFyKHcpLAogICAgWiA9IHZhcignWicpLCBTID0gdmFyKCdTJyksCiAgICBaZXJvPWluKDAsWiksIFN1Y2M9bGFtKHgsaW4oMCxTJFgpKSwKICAgIE4gPSB2YXIoJ04nKSwgQyA9IHZhcignQycpLAogICAgTmlsPWluKDAsTiksIENvbnM9bGFtKHgsbGFtKHhzLGluKDAsQyRYJHZhcih4cykpKSksCiAgICBCTiA9IHZhcignQk4nKSwgQkMgPSB2YXIoJ0JDJyksCiAgICBCTmlsPWluKDEsQk4pLCBCQ29ucz1sYW0oeCxsYW0oeHMsaW4oMSxCQyRYJHZhcih4cykpKSksCiAgICBUTV9pZCA9IGxhbSh4LFgpLAogICAgVE1fUyA9IGxhbSh4LGxhbSh5LGxhbSh3LChYJFcpJChZJFcpKSkpLAogICAgVE1fYmFkID0gbGFtKHgsWCRYKSwKICAgIFRNX2UxID0gbGV0KGlkPVRNX2lkLHZhcihpZCkkdmFyKGlkKSksCiAgICBUTV9lMiA9IGxhbSh5LGxldCh4PWxhbSh3LFkpLFgkWCkpLAogICAgVE1fZTNhID0gKEMkWmVybyROaWwpLAogICAgVE1fZTNmID0gWydOJy0+WmVybywnQycoeCx4cyktPlhdLCAlJSAkIChDJFplcm8kTmlsKSwKICAgIFRNX2UzID0gWydOJy0+WmVybywnQycoeCx4cyktPlhdICQgKEMkWmVybyROaWwpLAogICAgVE1fbGVuZHVtYjAgPSBtaXQobGVuLFsnTictPlplcm9dKSwKICAgIFRNX2xlbmR1bWIgPSBtaXQobGVuLFsnTictPlplcm8sJ0MnKHgseHMpLT5aZXJvXSksCiAgICBUTV9sZW4gPSBtaXQobGVuLFsnTictPlplcm8sJ0MnKHgseHMpLT5TdWNjJCh2YXIobGVuKSR2YXIoeHMpKV0pLAogICAgJSUgbGVuZ3RoIG9mIGxpc3QgZXhhbXBsZQogICAgVE1fZTQgPSBsZXQobGVuZ3RoPVRNX2xlbiwgQ29ucyQgKHZhcihsZW5ndGgpJChDb25zJFplcm8kTmlsKSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkIChDb25zJCAodmFyKGxlbmd0aCkkKENvbnMkTmlsJE5pbCkpICQgTmlsKSApLAogICAgJSUgc3VtIG9mIGJ1c2ggZXhhbXBsZQogICAgVE1fZTUgPSBtaXQoYnN1bSwgW0ldLS0+KChJLT5tdShOKSktPm11KE4pKSwKICAgICAgICAgICAgICAgWyAnQk4nICAgICAgIC0+IGxhbShmLFplcm8pCiAgICAgICAgICAgICAgICwgJ0JDJyh4LHhzKSAtPiBsYW0oZiwKICAgICAgICAgICAgICAgICAgICAgdmFyKHBsdXMpICQgKHZhcihmKSRYKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJCAodmFyKGJzdW0pICQgdmFyKHhzKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQgbGFtKHlzLHZhcihic3VtKSR2YXIoeXMpJHZhcihmKSkgKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICBdKSwKICAgIGFwcGVuZChLQzAsXyxLQzEpLCBjb3B5X3Rlcm0oQzAsQzEpLAogICAgdHlwZV9hbmRfcHJpbnQoS0MxLEMxLGxhbSh4LGxhbShuLFgkU3VjYyR2YXIobikpKSxfKSwgbmwsICEsCiAgICBhcHBlbmQoS0MwLF8sS0MyKSwgY29weV90ZXJtKEMwLEMyKSwKICAgIHR5cGVfYW5kX3ByaW50KEtDMixDMixUTV9lMyxfKSwgbmwsICEsCiAgICBhcHBlbmQoS0MwLF8sS0MzKSwgY29weV90ZXJtKEMwLEMzKSwKICAgIHR5cGVfYW5kX3ByaW50KEtDMyxDMyxUTV9sZW4sXyksIG5sLCAhLAogICAgYXBwZW5kKEtDMCxfLEtDNCksIGNvcHlfdGVybShDMCxDNCksCiAgICB0eXBlX2FuZF9wcmludChLQzQsQzQsVE1fZTQsXyksIG5sLCAhLAogICAgYXBwZW5kKEtDMCxfLEtDNSksIGNvcHlfdGVybShDMCxDNSksCiAgICB0eXBlX2FuZF9wcmludChLQzUsQzUsVE1fZTUsXyksIG5sLCAhLAogICAgdHJ1ZS4KCiUlIGhhdmVuJ3QgcmVhbGx5IHNob3duIGV4YW1wbGVzIG9mIHR5cGUgY29uc3RydWN0b3IgcG9seW1vcnBoc2ltIG9yCiUlIGtpbmQgcG9seW1vcnBoaXNtIGhlcmUgYnV0IHlvdSBnZXQgdGhlIGlkZWEgd2hhdCBzdHJ1Y3V0dXJhbCBleHRlbnNpb25zCiUlIHRvIEhNIGFyZSBuZWVkZWQgdG8gc3VwcG9ydCB0eXBlIGNvbnN0cnVjdG9yIGFuZCBraW5kIHBvbHltb3ByaGlzbXMuCgolJSBBdCB0aGlzIGxldmVsLCB0aGUgZXhhbXBsZXMgYXJlIGNvbXBsZXggZW5vdWdoLiBTbyBkb3dubG9hZGluZyBpdCBhbmQKJSUgcnVubmluZyBpdCBvbiB5b3VyIGxvY2FsIFNXSS1Qcm9sb2cgbWF5IGJlIG1vcmUgcGxlYXNhbnQgdG8gZXhwZXJpbWVudC4KJSUgWW91IG1heSBhbHNvIHdhbnQgYSBwYXJzZXIgYW5kIHByZXR0eSBwcmludGVyIGZvciBtaWNyb25heCBsYW5ndWFnZS4KCjotIG1haW4u