diff options
Diffstat (limited to 'lib')
276 files changed, 46503 insertions, 1267 deletions
diff --git a/lib/asn1/c_src/asn1_erl_driver.c b/lib/asn1/c_src/asn1_erl_driver.c index fd284e5800..9dd3a0fd7d 100644 --- a/lib/asn1/c_src/asn1_erl_driver.c +++ b/lib/asn1/c_src/asn1_erl_driver.c @@ -1407,7 +1407,6 @@ int decode_partial(ErlDrvBinary **drv_binary,unsigned char *in_buf, int in_buf_l int msg_index_val; int *msg_index, *tag_index, tmp_index; int tag_seq_length; - char tag_code; /* one of ASN1_SKIPPED, ASN1_OPTIONAL, ASN1_CHOOSEN */ int wanted_tag, next_tag; int buf_end_index = in_buf_len; int ret = 0, length, old_index; @@ -1600,7 +1599,7 @@ int get_value(char *out_buf, { int len, lenoflen, indef=0, skip_len; int ret=0; - int start_index, out_index = 0; + int start_index; /* printf("get_value 1\n\r"); */ if (in_buf[*msg_index] < 0x80){ /* short definite length */ diff --git a/lib/asn1/doc/src/asn1_ug.xml b/lib/asn1/doc/src/asn1_ug.xml index f2cd073ec8..12d986308f 100644 --- a/lib/asn1/doc/src/asn1_ug.xml +++ b/lib/asn1/doc/src/asn1_ug.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -22,7 +22,7 @@ </legalnotice> <title>Asn1</title> - <prepared>ETX/DN/SP Kenneth. Lundin</prepared> + <prepared>Kenneth Lundin</prepared> <docno></docno> <date>1999-03-25</date> <rev>D</rev> @@ -41,17 +41,28 @@ decode functions to be used by Erlang programs sending and receiving ASN.1 specified data.</item> <item>Run-time functions used by the generated code.</item> - <item>Encoding rules supported are <em>BER</em>, the - specialized BER version <em>DER</em> and the basic form of - aligned and unaligned variants of <em>PER</em>.</item> + <item>The supported encoding rules are: + <list> + <item> + Basic Encoding Rules (<em>BER</em>) + </item> + <item> + Distinguished Encoding Rules (<em>DER</em>), a specialized form of BER that is used in security-conscious applications. + </item> + <item> + Packed Encoding Rules (<em>PER</em>) both the aligned and unaligned variant. + </item> + </list> + </item> </list> </section> <section> <title>Overview</title> - <p>ASN.1 (Abstract Syntax Notation 1) defines the abstract - syntax of information. The purpose of ASN.1 is to have - a platform independent language to express types using a + <p>ASN.1 (Abstract Syntax Notation 1) is a formal language for describing data structures to be exchanged between distributed computer systems. + The purpose of ASN.1 is to have + a platform and programming language independent notation to express + types using a standardized set of rules for the transformation of values of a defined type, into a stream of bytes. This stream of bytes can then be sent on a communication channel set up by the @@ -102,20 +113,16 @@ [<cite id="DUBUISSON"></cite>], free to download at <url href="http://www.oss.com/asn1/dubuisson.html">http://www.oss.com/asn1/dubuisson.html </url>. </p> - <p>Knowledge of Erlang programming is also essential and reading the book - <em>Concurrent Programming in ERLANG</em>, - [<cite id="erlbook2"></cite>], is recommended. Part 1 of this is available on the web in - <url href="http://www.erlang.org/download/erlang-book-part1.pdf">PDF</url> format. - </p> </section> <section> <title>Capability</title> <p>This application covers all features of ASN.1 up to the 1997 - edition of the specification. In the 2002 edition some new - extensions came up of which there are support only for some of - them. ECN (Cncoding Control Notation) and XML notation are still - unsupported. Though, the other features of 2002 edition are + edition of the specification. In the 2002 edition of ASN.1 a number of + new features where introduced of which some are supported while + others are not. For example the + ECN (Encoding Control Notation) and XML notation are still + unsupported. Though, the other features of the 2002 edition are fully or partly supported as shown below:</p> <list type="bulleted"> <item> @@ -308,7 +315,7 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn <p>Choice of encoding rules, if omitted <c>ber</c> is the default. The <c>ber_bin</c> and <c>per_bin</c> options allows for optimizations and are therefore recommended - instaed of the <c>ber</c> and <c>per</c> options.</p> + instead of the <c>ber</c> and <c>per</c> options.</p> </item> <tag><c>-o OutDirectory</c></tag> <item> @@ -629,7 +636,7 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre> <c>driver</c> options does not affect the encode or decode result, just the time spent in run-time. When <c>ber_bin</c> and <c>driver</c> or <c>per_bin, optimize</c> and <c>driver</c> is - combined the C-code driver is used in choosen parts of encode / + combined the C-code driver is used in chosen parts of encode / decode procedure. </p> <table> @@ -749,11 +756,11 @@ asn1rt:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre> you may want to continue running the old asn1 run-time functionality.</item> <item>Performance issues: If you have an asn1 system with a lot - of cross references you may gain in performance. Meassurements + of cross references you may gain in performance. Measurements must be done for each case.</item> </list> <p>You may choose either the plain multi file compilation that just - merges the choosen asn1 specs or the <c>{inline,OutputModule}</c> + merges the chosen asn1 specs or the <c>{inline,OutputModule}</c> that also includes the used asn1 run-time functionality.</p> <p>For both cases you need to specify which asn1 specs you will compile in a module that must have the extension @@ -919,7 +926,7 @@ T5 ::= INTEGER (MIN<..-99) T6 ::= INTEGER {red(0),blue(1),white(2)} </pre> <p>The Erlang representation of an ASN.1 INTEGER is an integer or - an atom if a so called \011<c>Named NumberList</c> (see T6 above) + an atom if a so called <c>Named Number List</c> (see T6 above) is specified.</p> <p>Below is an example of Erlang code which assigns values for the above types: </p> @@ -934,7 +941,7 @@ T6value3 = white ASN.1 defined types. This style of value can be passed directly to the encoder for transformation into a series of bytes.</p> <p>The decoder will return an atom if the value corresponds to a - symbol in the Named NumberList.</p> + symbol in the Named Number List.</p> </section> <section> @@ -978,8 +985,9 @@ N1 = 'NULL', <p>The enumerated type can be used, when the value we wish to describe, may only take one of a set of predefined values.</p> <pre> -DaysOfTheWeek ::= ENUMERATED { sunday(1),monday(2),tuesday(3), -\011wednesday(4),thursday(5),friday(6),saturday(7) } +DaysOfTheWeek ::= ENUMERATED { + sunday(1),monday(2),tuesday(3), + wednesday(4),thursday(5),friday(6),saturday(7) } </pre> <p>For example to assign a weekday value in Erlang use the same atom as in the <c>Enumerations</c> of the type definition:</p> @@ -1273,11 +1281,14 @@ Pdu ::= SEQUENCE { <p>Values can be assigned in Erlang as shown below:</p> <pre> MyPdu = #'Pdu'{a=22,b=77.99,c={0,1,2,3,4},d='NULL'}. </pre> - <p>It is also possible to specify the value for each component in - a SEQUENCE or a SET as <c>{ComponentName,Value}</c>. It is not - recommended and is not supported if the flags <c>per_bin</c> or - <c>ber_bin</c> and <c>optimize</c> were used when the module was - compiled.</p> +<note> + <p> + In very early versions of the asn1 compiler it was also possible to + specify the values of the components in + a SEQUENCE or a SET as a list of tuples <c>{ComponentName,Value}</c>. + This is no longer supported. + </p> +</note> <p>The decode functions will return a record as result when decoding a <c>SEQUENCE</c> or a <c>SET</c>. <marker id="DEFAULT"></marker> @@ -1293,13 +1304,13 @@ MyPdu = #'Pdu'{a=22,b=77.99,c={0,1,2,3,4},d='NULL'}. </pre> <p>For instance, if the following types exists in a file "File.asn":</p> <pre> Seq1 ::= SEQUENCE { -\011a INTEGER DEFAULT 1, -\011b Seq2 DEFAULT {aa TRUE, bb 15} + a INTEGER DEFAULT 1, + b Seq2 DEFAULT {aa TRUE, bb 15} } Seq2 ::= SEQUENCE { -\011aa BOOLEAN, -\011bb INTEGER + aa BOOLEAN, + bb INTEGER } </pre> <p>Some values and the corresponding encoding in an Erlang terminal @@ -1331,7 +1342,7 @@ ok <marker id="DEFAULT DER"></marker> </p> <p>But, the DER encoding format has stronger requirements regarding - default\011values both for SET and SEQUENCE. A more elaborate and time + default values both for SET and SEQUENCE. A more elaborate and time expensive check of default values will take place. The following is an example with the same types and values as above but with der encoding format.</p> @@ -1409,7 +1420,7 @@ Bad ::= SET {i INTEGER, values is the same for SET as for SEQUENCE, and is supported by the compiler, <seealso marker="#DEFAULT DER">see above</seealso>.</p> <p>Moreover, in DER the elements of a SET will be sorted. If a - component is an untagged choice the sorting have to take place + component is an un-tagged choice the sorting have to take place in run-time. This fact emphasizes the following recommendation if DER encoding format is used.</p> <p>The concept of SET is an unusual @@ -1425,7 +1436,7 @@ Bad ::= SET {i INTEGER, </section> <section> - <title>Notes about Extendability for SEQUENCE and SET</title> + <title>Notes about Extend-ability for SEQUENCE and SET</title> <p>When a SEQUENCE or SET contains an extension marker and extension components like this:</p> <pre> @@ -1498,9 +1509,9 @@ C2 ::= CHOICE { <section> <title>Extendable CHOICE</title> <p>When a CHOICE contains an extension marker and the decoder detects - an unknown alternative of the CHIOCE the value is represented as:</p> + an unknown alternative of the CHOICE the value is represented as:</p> <pre> -\011 {asn1_ExtAlt, BytesForOpenType} +{asn1_ExtAlt, BytesForOpenType} </pre> <p>Where <c>BytesForOpenType</c> is a list of bytes constituting the encoding of the "unknown" CHOICE alternative. </p> @@ -1630,15 +1641,15 @@ V = #'Emb'{a=["qqqq",[1,2,255]], the record name is extended with an underscore and the component name. If the embedded structure is deeper with SEQUENCE, SET or CHOICE types in the line, each component-/alternative-name will - be added to the recordname.</p> + be added to the record-name.</p> <p>For example:</p> <pre> Seq ::= SEQUENCE{ - a\011CHOICE{ -\011b SEQUENCE { -\011 c INTEGER -\011 } -\011} + a CHOICE{ + b SEQUENCE { + c INTEGER + } + } } </pre> <p>will result in the following record:</p> <pre> @@ -1650,10 +1661,10 @@ Seq ::= SEQUENCE{ <pre> Seq ::= SEQUENCE { a SEQUENCE OF SEQUENCE { -\011 b + b } c SET OF SEQUENCE { -\011 d + d } } </pre> <p>This results in the records:</p> @@ -1802,16 +1813,16 @@ GENERAL-PROCEDURES GENERAL-PROCEDURE ::= { <pre> StartMessage ::= SEQUENCE { msgId GENERAL-PROCEDURE.&id ({GENERAL-PROCEDURES}), - content GENERAL-PROCEDURE.&Message\011({GENERAL-PROCEDURES}{@msgId}), + content GENERAL-PROCEDURE.&Message ({GENERAL-PROCEDURES}{@msgId}), } </pre> <p>In the type <c>StartMessage</c> the constraint following the <c>content</c> field tells that in a value of type <c>StartMessage</c> the value in the <c>content</c> field must - come from the same object that is choosen by the <c>msgId</c> + come from the same object that is chosen by the <c>msgId</c> field.</p> <p>So, the value <c>#'StartMessage'{msgId="home",content="Any Printable String"}</c> is legal to encode as a StartMessage value, while the value <c>#'StartMessage'{msgId="remote", content="Some String"}</c> is illegal since the constraint - in StartMessage tells that when you have choosen a value from a + in StartMessage tells that when you have chosen a value from a specific object in the object set GENERAL-PROCEDURES in the msgId field you have to choose a value from that same object in the content field too. In this second case it should have been @@ -1831,7 +1842,7 @@ StartMessage ::= SEQUENCE { information object sets. A part of a definition can be supplied as a parameter. For instance, if a Type is used in a definition with certain - purpose, one want the typename to express the intention. This + purpose, one want the type-name to express the intention. This can be done with parameterization.</p> <p>When many types (or an other ASN.1 entity) only differs in some minor cases, but the structure of the types are similar, only diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl index ae681a4a78..968468cb7f 100644 --- a/lib/asn1/src/asn1ct.erl +++ b/lib/asn1/src/asn1ct.erl @@ -1674,7 +1674,7 @@ create_pdec_inc_command(ModName, % [concat_sequential(lists:reverse(Comms), % [LastComm,CompAcc])|Acc] case lists:reverse(TagCommand) of - [Atom|Comms]�when is_atom(Atom) -> + [Atom|Comms] when is_atom(Atom) -> [concat_sequential(lists:reverse(Comms), [Atom,CompAcc])|Acc]; [[Command2,Tag2]|Comms] -> diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl index 1c9f2c759a..7cd29623c1 100644 --- a/lib/asn1/src/asn1ct_check.erl +++ b/lib/asn1/src/asn1ct_check.erl @@ -6408,6 +6408,12 @@ any_component_relation(S,Type,CNames,NamePath,Acc) when is_record(Type,type) -> [] end, InnerAcc ++ CRelPath ++ Acc; +%% Just skip the markers for ExtensionAdditionGroup start and end +%% in this function +any_component_relation(S,[#'ExtensionAdditionGroup'{}|Cs],CNames,NamePath,Acc) -> + any_component_relation(S,Cs,CNames,NamePath,Acc); +any_component_relation(S,['ExtensionAdditionGroupEnd'|Cs],CNames,NamePath,Acc) -> + any_component_relation(S,Cs,CNames,NamePath,Acc); any_component_relation(_,[],_,_,Acc) -> Acc. diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl index a55ac9db8e..e3be914af4 100644 --- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% Copyright Ericsson AB 2002-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -75,13 +75,15 @@ gen_encode_sequence(Erules,Typename,D) when is_record(D,type) -> "Val" end, - {SeqOrSet,TableConsInfo,CompList} = + {SeqOrSet,TableConsInfo,CompList0} = case D#type.def of #'SEQUENCE'{tablecinf=TCI,components=CL} -> {'SEQUENCE',TCI,CL}; #'SET'{tablecinf=TCI,components=CL} -> {'SET',TCI,CL} end, + %% filter away extensionAdditiongroup markers + CompList = filter_complist(CompList0), Ext = extensible(CompList), CompList1 = case CompList of {Rl1,El,Rl2} -> Rl1 ++ El ++ Rl2; @@ -183,7 +185,10 @@ gen_decode_sequence(Erules,Typename,D) when is_record(D,type) -> asn1ct_name:start(), asn1ct_name:clear(), asn1ct_name:new(tag), - #'SEQUENCE'{tablecinf=TableConsInfo,components=CList} = D#type.def, + #'SEQUENCE'{tablecinf=TableConsInfo,components=CList0} = D#type.def, + + %% filter away extensionAdditiongroup markers + CList = filter_complist(CList0), Ext = extensible(CList), {CompList,CompList2} = case CList of @@ -345,7 +350,9 @@ gen_decode_set(Erules,Typename,D) when is_record(D,type) -> asn1ct_name:clear(), %% asn1ct_name:new(term), asn1ct_name:new(tag), - #'SET'{tablecinf=TableConsInfo,components=TCompList} = D#type.def, + #'SET'{tablecinf=TableConsInfo,components=TCompList0} = D#type.def, + %% filter away extensionAdditiongroup markers + TCompList = filter_complist(TCompList0), Ext = extensible(TCompList), ToOptional = fun(mandatory) -> 'OPTIONAL'; @@ -1426,6 +1433,22 @@ extensible({RootList,ExtList}) -> {ext,length(RootList)+1,length(ExtList)}; extensible({_Rl1,_Ext,_Rl2}) -> extensible. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% filter away ExtensionAdditionGroup start and end marks since these +%% have no significance for the BER encoding +%% +filter_complist(CompList) when is_list(CompList) -> + lists:filter(fun(#'ExtensionAdditionGroup'{}) -> + false; + ('ExtensionAdditionGroupEnd') -> + false; + (_) -> + true + end, CompList); +filter_complist({Root,Ext}) -> + {Root,filter_complist(Ext)}; +filter_complist({Root1,Ext,Root2}) -> + {Root1,filter_complist(Ext),Root2}. print_attribute_comment(InnerType,Pos,Cname,Prop) -> diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl index 6b511a66da..0bb0b65e5d 100644 --- a/lib/asn1/src/asn1ct_gen.erl +++ b/lib/asn1/src/asn1ct_gen.erl @@ -537,33 +537,18 @@ gen_part_decode_funcs(WhatKind,_TypeName,{_,Directive,_,_}) -> throw({error,{asn1,{"Not implemented yet",WhatKind," partial incomplete directive:",Directive}}}). -extaddgroup2sequence(ExtList) -> - extaddgroup2sequence(ExtList,[]). - -extaddgroup2sequence([{'ExtensionAdditionGroup',Number0}|T],Acc) -> - Number = case Number0 of undefined -> 1; _ -> Number0 end, - {ExtGroupComps,['ExtensionAdditionGroupEnd'|T2]} = - lists:splitwith(fun(Elem) -> is_record(Elem,'ComponentType') end,T), - extaddgroup2sequence(T2,[#'ComponentType'{ - name='ExtAddGroup', - typespec=#type{def=#'SEQUENCE'{ - extaddgroup=Number, - components=ExtGroupComps}}, - prop='OPTIONAL'}|Acc]); -extaddgroup2sequence([C|T],Acc) -> - extaddgroup2sequence(T,[C|Acc]); -extaddgroup2sequence([],Acc) -> - lists:reverse(Acc). - - gen_types(Erules,Tname,{RootL1,ExtList,RootL2}) when is_list(RootL1), is_list(RootL2) -> gen_types(Erules,Tname,RootL1), - gen_types(Erules,Tname,extaddgroup2sequence(ExtList)), + Rtmod = list_to_atom(lists:concat(["asn1ct_gen_",erule(Erules), + rt2ct_suffix(Erules)])), + gen_types(Erules,Tname,Rtmod:extaddgroup2sequence(ExtList)), gen_types(Erules,Tname,RootL2); gen_types(Erules,Tname,{RootList,ExtList}) when is_list(RootList) -> gen_types(Erules,Tname,RootList), - gen_types(Erules,Tname,extaddgroup2sequence(ExtList)); + Rtmod = list_to_atom(lists:concat(["asn1ct_gen_",erule(Erules), + rt2ct_suffix(Erules)])), + gen_types(Erules,Tname,Rtmod:extaddgroup2sequence(ExtList)); gen_types(Erules,Tname,[{'EXTENSIONMARK',_,_}|Rest]) -> gen_types(Erules,Tname,Rest); gen_types(Erules,Tname,[ComponentType|Rest]) -> diff --git a/lib/asn1/src/asn1ct_gen_ber.erl b/lib/asn1/src/asn1ct_gen_ber.erl index d70586c75c..491ebcb8fd 100644 --- a/lib/asn1/src/asn1ct_gen_ber.erl +++ b/lib/asn1/src/asn1ct_gen_ber.erl @@ -33,6 +33,7 @@ -export([gen_objectset_code/2, gen_obj_code/3]). -export([re_wrap_erule/1]). -export([unused_var/2]). +-export([extaddgroup2sequence/1]). -import(asn1ct_gen, [emit/1,demit/1]). @@ -1734,3 +1735,15 @@ get_object_field(Name,ObjectFields) -> {value,Field} -> Field; false -> false end. + +%% For BER the ExtensionAdditionGroup notation has no impact on the encoding/decoding +%% and therefore we only filter away the ExtensionAdditionGroup start and end markers +%% +extaddgroup2sequence(ExtList) when is_list(ExtList) -> + lists:filter(fun(#'ExtensionAdditionGroup'{}) -> + false; + ('ExtensionAdditionGroupEnd') -> + false; + (_) -> + true + end, ExtList). diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl index a146e92d64..9ec458e351 100644 --- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl +++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl @@ -33,6 +33,7 @@ -export([gen_objectset_code/2, gen_obj_code/3]). -export([encode_tag_val/3]). -export([gen_inc_decode/2,gen_decode_selected/3]). +-export([extaddgroup2sequence/1]). -import(asn1ct_gen, [emit/1,demit/1]). @@ -1826,8 +1827,15 @@ mk_object_val(Val, Ack, Len) -> add_func(F={_Func,_Arity}) -> ets:insert(asn1_functab,{F}). - - - +%% For BER the ExtensionAdditionGroup notation has no impact on the encoding/decoding +%% and therefore we only filter away the ExtensionAdditionGroup start and end markers +extaddgroup2sequence(ExtList) when is_list(ExtList) -> + lists:filter(fun(#'ExtensionAdditionGroup'{}) -> + false; + ('ExtensionAdditionGroupEnd') -> + false; + (_) -> + true + end, ExtList). diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl index 23fb392d60..8313cf1b60 100644 --- a/lib/asn1/src/asn1ct_gen_per.erl +++ b/lib/asn1/src/asn1ct_gen_per.erl @@ -31,6 +31,7 @@ -export([gen_encode/2, gen_encode/3]). -export([is_already_generated/2,more_genfields/1,get_class_fields/1, get_object_field/2]). +-export([extaddgroup2sequence/1]). -import(asn1ct_gen, [emit/1,demit/1]). @@ -1393,3 +1394,25 @@ get_object_field(Name,ObjectFields) -> false -> false end. + +%% For PER the ExtensionAdditionGroup notation has significance for the encoding and decoding +%% the components within the ExtensionAdditionGroup is treated in a similar way as if they +%% have been specified within a SEQUENCE, therefore we construct a fake sequence type here +%% so that we can generate code for it +extaddgroup2sequence(ExtList) -> + extaddgroup2sequence(ExtList,[]). + +extaddgroup2sequence([{'ExtensionAdditionGroup',Number0}|T],Acc) -> + Number = case Number0 of undefined -> 1; _ -> Number0 end, + {ExtGroupComps,['ExtensionAdditionGroupEnd'|T2]} = + lists:splitwith(fun(Elem) -> is_record(Elem,'ComponentType') end,T), + extaddgroup2sequence(T2,[#'ComponentType'{ + name='ExtAddGroup', + typespec=#type{def=#'SEQUENCE'{ + extaddgroup=Number, + components=ExtGroupComps}}, + prop='OPTIONAL'}|Acc]); +extaddgroup2sequence([C|T],Acc) -> + extaddgroup2sequence(T,[C|Acc]); +extaddgroup2sequence([],Acc) -> + lists:reverse(Acc). diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl index e1feb42a59..4f4fcfafc3 100644 --- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl +++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl @@ -29,6 +29,7 @@ -export([gen_obj_code/3,gen_objectset_code/2]). -export([gen_decode/2, gen_decode/3]). -export([gen_encode/2, gen_encode/3]). +-export([extaddgroup2sequence/1]). -import(asn1ct_gen, [emit/1,demit/1]). -import(asn1ct_gen_per, [is_already_generated/2,more_genfields/1, @@ -1796,3 +1797,25 @@ dec_enumerated_cases([Name|Rest],Tmpremain,No) -> dec_enumerated_cases(Rest,Tmpremain,No+1); dec_enumerated_cases([],_,_) -> "". + +%% For PER the ExtensionAdditionGroup notation has significance for the encoding and decoding +%% the components within the ExtensionAdditionGroup is treated in a similar way as if they +%% have been specified within a SEQUENCE, therefore we construct a fake sequence type here +%% so that we can generate code for it +extaddgroup2sequence(ExtList) -> + extaddgroup2sequence(ExtList,[]). + +extaddgroup2sequence([{'ExtensionAdditionGroup',Number0}|T],Acc) -> + Number = case Number0 of undefined -> 1; _ -> Number0 end, + {ExtGroupComps,['ExtensionAdditionGroupEnd'|T2]} = + lists:splitwith(fun(Elem) -> is_record(Elem,'ComponentType') end,T), + extaddgroup2sequence(T2,[#'ComponentType'{ + name='ExtAddGroup', + typespec=#type{def=#'SEQUENCE'{ + extaddgroup=Number, + components=ExtGroupComps}}, + prop='OPTIONAL'}|Acc]); +extaddgroup2sequence([C|T],Acc) -> + extaddgroup2sequence(T,[C|Acc]); +extaddgroup2sequence([],Acc) -> + lists:reverse(Acc). diff --git a/lib/asn1/src/asn1rt_uper_bin.erl b/lib/asn1/src/asn1rt_uper_bin.erl index a964b835ae..abe178a69e 100644 --- a/lib/asn1/src/asn1rt_uper_bin.erl +++ b/lib/asn1/src/asn1rt_uper_bin.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% Copyright Ericsson AB 2008-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1611,25 +1611,8 @@ complete_NFP(InList) when is_bitstring(InList) -> %% 10.5.6 NOTE: If "range" satisfies the inequality 2^m < "range" =< %% 2^(m+1) then the number of bits = m + 1 -num_bits(1) -> 0; -num_bits(2) -> 1; -num_bits(R) when R =< 4 -> - 2; -num_bits(R) when R =< 8 -> - 3; -num_bits(R) when R =< 16 -> - 4; -num_bits(R) when R =< 32 -> - 5; -num_bits(R) when R =< 64 -> - 6; -num_bits(R) when R =< 128 -> - 7; -num_bits(R) when R =< 256 -> - 8; -num_bits(R) when R =< 512 -> - 9; -num_bits(R) when R =< 1024 -> - 10; -num_bits(R) -> - 1+num_bits(R bsr 1). + +num_bits(N) -> + num_bits(N,1,0). +num_bits(N,T,B) when N=<T->B; +num_bits(N,T,B) ->num_bits(N,T bsl 1, B+1). diff --git a/lib/asn1/test/asn1_SUITE.erl.src b/lib/asn1/test/asn1_SUITE.erl.src index f0228546a5..fad094c988 100644 --- a/lib/asn1/test/asn1_SUITE.erl.src +++ b/lib/asn1/test/asn1_SUITE.erl.src @@ -2299,11 +2299,12 @@ testExtensionAdditionGroup(Config) -> ?line Path = code:get_path(), ?line code:add_patha(PrivDir), DoIt = fun(Erule) -> - ?line ok = asn1ct:compile(filename:join(DataDir,"Extension-Addition-Group"),[Erule,{outdir,PrivDir}]), + ?line ok = asn1ct:compile(filename:join(DataDir,"Extension-Addition-Group"),Erule ++ [{outdir,PrivDir}]), ?line {ok,_M} = compile:file(filename:join(DataDir,"extensionAdditionGroup"),[{i,PrivDir},{outdir,PrivDir},debug_info]), - ?line ok = extensionAdditionGroup:run(Erule) + ?line ok = extensionAdditionGroup:run(Erule), + ?line ok = extensionAdditionGroup:run2(Erule) end, - ?line [DoIt(Rule)|| Rule <- [per_bin,uper_bin,ber_bin]], + ?line [DoIt(Rule)|| Rule <- [[per_bin],[per_bin,optimize],[uper_bin],[ber_bin],[ber_bin,optimize]]], ?line code:set_path(Path). diff --git a/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn b/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn index b985c970ac..fc244c30a2 100644 --- a/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn +++ b/lib/asn1/test/asn1_SUITE_data/Extension-Addition-Group.asn @@ -48,6 +48,7 @@ Ax ::= SEQUENCE { } -- valAx Ax ::= { a 253, b TRUE, c e: TRUE, g "123", h TRUE } + Ax2 ::= SEQUENCE { a INTEGER (250..253), b BOOLEAN, @@ -55,7 +56,6 @@ Ax2 ::= SEQUENCE { ug NumericString } -END -- The value { a 253, b TRUE, c e: TRUE, g "123", h TRUE } -- is encoded in PER as @@ -64,3 +64,19 @@ END -- is encoded in Unaligned PER as -- 9E000600 040A4690 + +Ax3 ::= SEQUENCE { + a INTEGER (250..253), + b BOOLEAN, + s SEQUENCE { + sa INTEGER, + sb BOOLEAN, + ..., + [[ + sextaddgroup INTEGER OPTIONAL + ]] + } +} + +-- { a 253, b TRUE, s {sa 17, sb TRUE, sextaddgroup 11}} +END diff --git a/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl b/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl index 79e200f561..c86c787610 100644 --- a/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl +++ b/lib/asn1/test/asn1_SUITE_data/extensionAdditionGroup.erl @@ -41,3 +41,16 @@ run(Erule) -> Val -> ok; _ -> exit({expected,Val, got, Val2}) end. + +run2(Erule) -> + Val = #'Ax3'{a=253, b = true, s = #'Ax3_s'{sa = 11, sb = true, sextaddgroup = 17}}, + io:format("~p:~p~n",[Erule,Val]), + {ok,List}= asn1rt:encode('Extension-Addition-Group','Ax3',Val), + Enc = iolist_to_binary(List), + io:format("~p~n",[Enc]), + {ok,Val2} = asn1rt:decode('Extension-Addition-Group','Ax3',Enc), + io:format("~p~n",[Val2]), + case Val2 of + Val -> ok; + _ -> exit({expected,Val, got, Val2}) + end. diff --git a/lib/asn1/test/test_compile_options.erl b/lib/asn1/test/test_compile_options.erl index 83f38c5e6d..5e027cdedb 100644 --- a/lib/asn1/test/test_compile_options.erl +++ b/lib/asn1/test/test_compile_options.erl @@ -132,7 +132,7 @@ verbose(Config) when is_list(Config) -> ?line ok = asn1ct:compile(Asn1File, [{i,DataDir},{outdir,OutDir},noobj,verbose]), ?line test_server:capture_stop(), ?line [Line0|_] = test_server:capture_get(), - ?line lists:prefix("Erlang ASN.1 version", Line0), + ?line true = lists:prefix("Erlang ASN.1 version", Line0), %% Test non-verbose compile ?line test_server:capture_start(), diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl index dc6fcc66e5..6b75937668 100644 --- a/lib/common_test/src/ct_config.erl +++ b/lib/common_test/src/ct_config.erl @@ -48,7 +48,7 @@ -export([get_ref_from_name/1, get_name_from_ref/1, get_key_from_name/1]). --export([check_config_files/1, prepare_config_list/1]). +-export([check_config_files/1, add_default_callback/1, prepare_config_list/1]). -export([add_config/2, remove_config/2]). @@ -212,6 +212,24 @@ get_config_file_list(Opts) -> process_user_configs(Opts, []), CfgFiles. +add_default_callback(Opts) -> + case lists:keytake(config, 1, Opts) of + {value, {config, [File | _] = Files}, NoConfigOpts} + when is_integer(File) =/= true -> + [{config, lists:flatmap(fun add_def_cb/1, Files)} | NoConfigOpts]; + {value, {config, File}, NoConfigOpts} -> + [{config, add_def_cb(File)} | NoConfigOpts]; + false -> + Opts + end. + +add_def_cb([]) -> + []; +add_def_cb(Config) when is_tuple(Config) -> + [Config]; +add_def_cb([H|_T] = Config ) when is_integer(H) -> + [{?ct_config_txt, [Config]}]. + read_config_files(Opts) -> AddCallback = fun(CallBack, []) -> [{CallBack, []}]; @@ -220,16 +238,16 @@ read_config_files(Opts) -> (CallBack, [F|_]=Files) when is_list(F) -> lists:map(fun(X) -> {CallBack, X} end, Files) end, + ConfigFiles = case lists:keyfind(config, 1, Opts) of - {config, ConfigLists}-> - lists:foldr(fun({Callback,Files}, Acc) -> - AddCallback(Callback,Files) ++ Acc - end, - [], - ConfigLists); - false-> - [] - end, + {config,ConfigLists}-> + lists:foldr(fun({Callback,Files}, Acc) -> + AddCallback(Callback,Files) + ++ Acc + end,[],ConfigLists); + false-> + [] + end, read_config_files_int(ConfigFiles, fun store_config/3). read_config_files_int([{Callback, File}|Files], FunToSave) -> diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index c716111f4d..f8ace73cbf 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -384,11 +384,14 @@ maybe_log_timestamp() -> [{"<i>~s</i>",[log_timestamp({MS,S,US})]}]}) end. -log_timestamp(Now) -> - put(log_timestamp,Now), - {_,{H,M,S}} = calendar:now_to_local_time(Now), - lists:flatten(io_lib:format("~2.2.0w:~2.2.0w:~2.2.0w", - [H,M,S])). +log_timestamp({MS,S,US}) -> + put(log_timestamp, {MS,S,US}), + {{Year,Month,Day}, {Hour,Min,Sec}} = + calendar:now_to_local_time({MS,S,US}), + MilliSec = trunc(US/1000), + lists:flatten(io_lib:format("~4.10.0B-~2.10.0B-~2.10.0B " + "~2.10.0B:~2.10.0B:~2.10.0B.~3.10.0B", + [Year,Month,Day,Hour,Min,Sec,MilliSec])). %%%----------------------------------------------------------------- %%% The logger server diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index 62d73ecbbf..586b3893f1 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -550,6 +550,9 @@ install(Opts) -> install(Opts, "."). install(Opts, LogDir) -> + + ConfOpts = ct_config:add_default_callback(Opts), + case application:get_env(common_test, decrypt) of {ok,_} -> ok; @@ -566,7 +569,7 @@ install(Opts, LogDir) -> VarFile = variables_file_name(LogDir), case file:open(VarFile, [write]) of {ok,Fd} -> - [io:format(Fd, "~p.\n", [Opt]) || Opt <- Opts], + [io:format(Fd, "~p.\n", [Opt]) || Opt <- ConfOpts ], file:close(Fd), ok; {error,Reason} -> diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile index b96bdef5e0..f2fe3390cf 100644 --- a/lib/common_test/test/Makefile +++ b/lib/common_test/test/Makefile @@ -94,7 +94,7 @@ release_spec: opt release_tests_spec: $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(ERL_FILES) $(COVERFILE) $(RELSYSDIR) - $(INSTALL_PROGRAM) common_test.spec $(RELSYSDIR) + $(INSTALL_DATA) common_test.spec $(RELSYSDIR) chmod -f -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) diff --git a/lib/common_test/test/ct_config_SUITE.erl b/lib/common_test/test/ct_config_SUITE.erl index 72ff781f82..fc15abc5bc 100644 --- a/lib/common_test/test/ct_config_SUITE.erl +++ b/lib/common_test/test/ct_config_SUITE.erl @@ -58,6 +58,9 @@ end_per_suite(Config) -> init_per_testcase(TestCase, Config) -> ct_test_support:init_per_testcase(TestCase, Config). +end_per_testcase(install_config = TestCase, Config) -> + ok = rpc:call(proplists:get_value(ct_node, Config), ct_config, stop, []), + ct_test_support:end_per_testcase(TestCase, Config); end_per_testcase(TestCase, Config) -> ct_test_support:end_per_testcase(TestCase, Config). @@ -66,12 +69,13 @@ all(doc) -> all(suite) -> [ - require, - userconfig_static, - userconfig_dynamic, - testspec_legacy, - testspec_static, - testspec_dynamic + require, + install_config, + userconfig_static, + userconfig_dynamic, + testspec_legacy, + testspec_static, + testspec_dynamic ]. %%-------------------------------------------------------------------- @@ -84,6 +88,17 @@ require(Config) when is_list(Config) -> {config, filename:join(DataDir, "config/config.txt")}, ["config_static_SUITE"]). +install_config(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + CTNode = proplists:get_value(ct_node, Config), + rpc:call(CTNode, ct, install, + [[{config, [filename:join(DataDir, "config/config.txt")]}]]), + case rpc:call(CTNode, ct_config, start, [interactive]) of + Pid when is_pid(Pid) -> + ok + end. + + userconfig_static(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), run_test(config_static_SUITE, @@ -135,6 +150,8 @@ testspec_dynamic(Config) when is_list(Config) -> []), file:delete(filename:join(ConfigDir, "spec_dynamic.spec")). + + %%%----------------------------------------------------------------- %%% HELP FUNCTIONS %%%----------------------------------------------------------------- diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in index e728db18eb..040adcfd09 100644 --- a/lib/crypto/c_src/Makefile.in +++ b/lib/crypto/c_src/Makefile.in @@ -68,13 +68,13 @@ RELSYSDIR = $(RELEASE_PATH)/lib/crypto-$(VSN) # ---------------------------------------------------- # Misc Macros # ---------------------------------------------------- -OBJS = $(OBJDIR)/crypto.o +OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o NIF_MAKEFILE = $(PRIVDIR)/Makefile ifeq ($(findstring win32,$(TARGET)), win32) -NIF_LIB = $(LIBDIR)/crypto.dll +NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).dll else -NIF_LIB = $(LIBDIR)/crypto.so +NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).so endif ifeq ($(HOST_OS),) @@ -102,20 +102,30 @@ $(OBJDIR): $(LIBDIR): -@mkdir -p $(LIBDIR) -$(OBJDIR)/%.o: %.c +$(OBJDIR)/%$(TYPEMARKER).o: %.c $(INSTALL_DIR) $(OBJDIR) $(CC) -c -o $@ $(ALL_CFLAGS) $< -$(LIBDIR)/crypto.so: $(OBJS) +$(LIBDIR)/crypto$(TYPEMARKER).so: $(OBJS) $(INSTALL_DIR) $(LIBDIR) $(LD) $(LDFLAGS) -o $@ $^ $(LDLIBS) $(CRYPTO_LINK_LIB) -$(LIBDIR)/crypto.dll: $(OBJS) +$(LIBDIR)/crypto$(TYPEMARKER).dll: $(OBJS) $(INSTALL_DIR) $(LIBDIR) $(LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(OBJS) -llibeay32 clean: - rm -f $(NIF_LIB) $(OBJS) +ifeq ($(findstring win32,$(TARGET)), win32) + rm -f $(LIBDIR)/crypto.dll + rm -f $(LIBDIR)/crypto.debug.dll +else + rm -f $(LIBDIR)/crypto.so + rm -f $(LIBDIR)/crypto.debug.so + rm -f $(LIBDIR)/crypto.valgrind.so +endif + rm -f $(OBJDIR)/crypto.o + rm -f $(OBJDIR)/crypto.debug.o + rm -f $(OBJDIR)/crypto.valgrind.o rm -f core *~ docs: diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 8823bba3b6..85614a84c2 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -64,8 +64,8 @@ # define ERL_VALGRIND_ASSERT_MEM_DEFINED(ptr,size) \ ((void) ((VALGRIND_CHECK_MEM_IS_DEFINED(ptr,size) == 0) ? 1 : \ - (fprintf(stderr,"\r\n####### VALGRIND_ASSSERT(%p,%d) failed at %s:%d\r\n",\ - (ptr),(size), __FILE__, __LINE__), abort(), 0))) + (fprintf(stderr,"\r\n####### VALGRIND_ASSSERT(%p,%ld) failed at %s:%d\r\n",\ + (ptr),(long)(size), __FILE__, __LINE__), abort(), 0))) #else # define ERL_VALGRIND_MAKE_MEM_DEFINED(ptr,size) # define ERL_VALGRIND_ASSERT_MEM_DEFINED(ptr,size) @@ -706,12 +706,13 @@ static int get_bn_from_mpint(ErlNifEnv* env, ERL_NIF_TERM term, BIGNUM** bnp) static ERL_NIF_TERM rand_uniform_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Lo,Hi) */ - BIGNUM *bn_from, *bn_to, *bn_rand; + BIGNUM *bn_from = NULL, *bn_to, *bn_rand; unsigned char* data; unsigned dlen; ERL_NIF_TERM ret; if (!get_bn_from_mpint(env, argv[0], &bn_from) || !get_bn_from_mpint(env, argv[1], &bn_rand)) { + if (bn_from) BN_free(bn_from); return enif_make_badarg(env); } @@ -770,7 +771,7 @@ static int inspect_mpint(ErlNifEnv* env, ERL_NIF_TERM term, ErlNifBinary* bin) static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (DigestType,Data,Signature,Key=[P, Q, G, Y]) */ ErlNifBinary data_bin, sign_bin; - BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_y; + BIGNUM *dsa_p = NULL, *dsa_q = NULL, *dsa_g = NULL, *dsa_y = NULL; unsigned char hmacbuf[SHA_DIGEST_LENGTH]; ERL_NIF_TERM head, tail; DSA *dsa; @@ -786,6 +787,11 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_mpint(env, head, &dsa_y) || !enif_is_empty_list(env,tail)) { + badarg: + if (dsa_p) BN_free(dsa_p); + if (dsa_q) BN_free(dsa_q); + if (dsa_g) BN_free(dsa_g); + if (dsa_y) BN_free(dsa_y); return enif_make_badarg(env); } if (argv[0] == atom_sha && inspect_mpint(env, argv[1], &data_bin)) { @@ -796,7 +802,7 @@ static ERL_NIF_TERM dss_verify(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv memcpy(hmacbuf, data_bin.data, SHA_DIGEST_LENGTH); } else { - return enif_make_badarg(env); + goto badarg; } dsa = DSA_new(); @@ -1119,7 +1125,7 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER enif_alloc_binary(RSA_size(rsa), &ret_bin); if (argv[3] == atom_true) { - ERL_VALGRIND_ASSERT_MEM_DEFINED(buf+i,data_len); + ERL_VALGRIND_ASSERT_MEM_DEFINED(data_bin.data,data_bin.size); i = RSA_public_encrypt(data_bin.size, data_bin.data, ret_bin.data, rsa, padding); if (i > 0) { @@ -1139,6 +1145,7 @@ static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TER return enif_make_binary(env,&ret_bin); } else { + enif_release_binary(&ret_bin); return atom_error; } } @@ -1167,7 +1174,7 @@ static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE enif_alloc_binary(RSA_size(rsa), &ret_bin); if (argv[3] == atom_true) { - ERL_VALGRIND_ASSERT_MEM_DEFINED(buf+i,data_len); + ERL_VALGRIND_ASSERT_MEM_DEFINED(data_bin.data,data_bin.size); i = RSA_private_encrypt(data_bin.size, data_bin.data, ret_bin.data, rsa, padding); if (i > 0) { @@ -1187,6 +1194,7 @@ static ERL_NIF_TERM rsa_private_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TE return enif_make_binary(env,&ret_bin); } else { + enif_release_binary(&ret_bin); return atom_error; } } @@ -1266,7 +1274,7 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_ || !enif_get_list_cell(env, tail, &head, &tail) || !get_bn_from_mpint(env, head, &dh_params->g) || !enif_is_empty_list(env, tail)) { - + DH_free(dh_params); return enif_make_badarg(env); } @@ -1293,7 +1301,7 @@ static ERL_NIF_TERM dh_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (OthersPublicKey, MyPrivateKey, DHParams=[P,G]) */ DH* dh_params = DH_new(); - BIGNUM* pubkey; + BIGNUM* pubkey = NULL; int i; ErlNifBinary ret_bin; ERL_NIF_TERM ret, head, tail; @@ -1321,6 +1329,7 @@ static ERL_NIF_TERM dh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_T ret = atom_error; } } + if (pubkey) BN_free(pubkey); DH_free(dh_params); return ret; } diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index 19fa495b7d..71fd91cafd 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -93,22 +93,42 @@ -define(CRYPTO_NIF_VSN,101). on_load() -> - LibName = "crypto", + LibBaseName = "crypto", PrivDir = code:priv_dir(crypto), - Lib1 = filename:join([PrivDir, "lib", LibName]), - Status = case erlang:load_nif(Lib1, ?CRYPTO_NIF_VSN) of + LibName = case erlang:system_info(build_type) of + opt -> + LibBaseName; + Type -> + LibTypeName = LibBaseName ++ "." ++ atom_to_list(Type), + case (filelib:wildcard( + filename:join( + [PrivDir, + "lib", + LibTypeName ++ "*"])) /= []) orelse + (filelib:wildcard( + filename:join( + [PrivDir, + "lib", + erlang:system_info(system_architecture), + LibTypeName ++ "*"])) /= []) of + true -> LibTypeName; + false -> LibBaseName + end + end, + Lib = filename:join([PrivDir, "lib", LibName]), + Status = case erlang:load_nif(Lib, ?CRYPTO_NIF_VSN) of ok -> ok; {error, {load_failed, _}}=Error1 -> - LibDir2 = + ArchLibDir = filename:join([PrivDir, "lib", erlang:system_info(system_architecture)]), Candidate = - filelib:wildcard(filename:join([LibDir2,LibName ++ "*" ])), + filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])), case Candidate of [] -> Error1; _ -> - Lib2 = filename:join([LibDir2, LibName]), - erlang:load_nif(Lib2, ?CRYPTO_NIF_VSN) + ArchLib = filename:join([ArchLibDir, LibName]), + erlang:load_nif(ArchLib, ?CRYPTO_NIF_VSN) end; Error1 -> Error1 end, @@ -119,7 +139,6 @@ on_load() -> "OpenSSL might not be installed on this system.~n",[E,Str]), Status end. - nif_stub_error(Line) -> erlang:nif_error({nif_not_loaded,module,?MODULE,line,Line}). diff --git a/lib/debugger/test/Makefile b/lib/debugger/test/Makefile new file mode 100644 index 0000000000..ac929038f7 --- /dev/null +++ b/lib/debugger/test/Makefile @@ -0,0 +1,106 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1998-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES= \ + andor_SUITE \ + bs_bincomp_SUITE \ + bs_construct_SUITE \ + bs_match_bin_SUITE \ + bs_match_int_SUITE \ + bs_match_misc_SUITE \ + bs_match_tail_SUITE \ + bs_utf_SUITE \ + bug_SUITE \ + erl_eval_SUITE \ + dbg_ui_SUITE \ + debugger_SUITE \ + int_SUITE \ + int_break_SUITE \ + int_eval_SUITE \ + guard_SUITE \ + exception_SUITE \ + fun_SUITE \ + lc_SUITE \ + record_SUITE \ + trycatch_SUITE \ + test_lib \ + cleanup + +ERL_FILES= $(MODULES:%=%.erl) + +TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) +INSTALL_PROGS= $(TARGET_FILES) + +EMAKEFILE=Emakefile + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/debugger_test + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- + +ERL_MAKE_FLAGS += +ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include + +EBIN = . + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +make_emakefile: + $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \ + > $(EMAKEFILE) + $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' \ + >> $(EMAKEFILE) + +tests debug opt: make_emakefile + erl $(ERL_MAKE_FLAGS) -make + +clean: + rm -f $(EMAKEFILE) + rm -f $(TARGET_FILES) $(GEN_FILES) + rm -f core + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + +release_tests_spec: make_emakefile + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR) + $(INSTALL_DATA) debugger.spec $(RELSYSDIR) + chmod -f -R u+w $(RELSYSDIR) + @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) + +release_docs_spec: diff --git a/lib/debugger/test/andor_SUITE.erl b/lib/debugger/test/andor_SUITE.erl new file mode 100644 index 0000000000..3482a22a34 --- /dev/null +++ b/lib/debugger/test/andor_SUITE.erl @@ -0,0 +1,305 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(andor_SUITE). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + t_andalso/1,t_orelse/1,inside/1,overlap/1, + combined/1,in_case/1]). + +-include("test_server.hrl"). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + ?line Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +cases() -> + [t_andalso,t_orelse,inside,overlap,combined,in_case]. + +t_andalso(Config) when is_list(Config) -> + Bs = [true,false], + Ps = [{X,Y} || X <- Bs, Y <- Bs], + lists:foreach(fun (P) -> t_andalso_1(P) end, Ps), + + ?line true = true andalso true, + ?line false = true andalso false, + ?line false = false andalso true, + ?line false = false andalso false, + + ?line false = false andalso glurf, + ?line false = false andalso exit(exit_now), + + ?line true = not id(false) andalso not id(false), + ?line false = not id(false) andalso not id(true), + ?line false = not id(true) andalso not id(false), + ?line false = not id(true) andalso not id(true), + + ?line {'EXIT',{badarg,_}} = (catch not id(glurf) andalso id(true)), + ?line {'EXIT',{badarg,_}} = (catch not id(false) andalso not id(glurf)), + ?line false = id(false) andalso not id(glurf), + ?line false = false andalso not id(glurf), + + ok. + +t_orelse(Config) when is_list(Config) -> + Bs = [true,false], + Ps = [{X,Y} || X <- Bs, Y <- Bs], + lists:foreach(fun (P) -> t_orelse_1(P) end, Ps), + + ?line true = true orelse true, + ?line true = true orelse false, + ?line true = false orelse true, + ?line false = false orelse false, + + ?line true = true orelse glurf, + ?line true = true orelse exit(exit_now), + + ?line true = not id(false) orelse not id(false), + ?line true = not id(false) orelse not id(true), + ?line true = not id(true) orelse not id(false), + ?line false = not id(true) orelse not id(true), + + ?line {'EXIT',{badarg,_}} = (catch not id(glurf) orelse id(true)), + ?line {'EXIT',{badarg,_}} = (catch not id(true) orelse not id(glurf)), + ?line true = id(true) orelse not id(glurf), + ?line true = true orelse not id(glurf), + + ok. + +t_andalso_1({X,Y}) -> + io:fwrite("~w andalso ~w: ",[X,Y]), + V1 = echo(X) andalso echo(Y), + V1 = if + X andalso Y -> true; + true -> false + end, + check(V1, X and Y). + +t_orelse_1({X,Y}) -> + io:fwrite("~w orelse ~w: ",[X,Y]), + V1 = echo(X) orelse echo(Y), + V1 = if + X orelse Y -> true; + true -> false + end, + check(V1, X or Y). + +inside(Config) when is_list(Config) -> + ?line true = inside(-8, 1), + ?line false = inside(-53.5, -879798), + ?line false = inside(1.0, -879), + ?line false = inside(59, -879), + ?line false = inside(-11, 1.0), + ?line false = inside(100, 0.2), + ?line false = inside(100, 1.2), + ?line false = inside(-53.5, 4), + ?line false = inside(1.0, 5.3), + ?line false = inside(59, 879), + ok. + +inside(Xm, Ym) -> + X = -10.0, + Y = -2.0, + W = 20.0, + H = 4.0, + Res = inside(Xm, Ym, X, Y, W, H), + Res = if + X =< Xm andalso Xm < X+W andalso Y =< Ym andalso Ym < Y+H -> true; + true -> false + end, + case not id(Res) of + Outside -> + Outside = if + not(X =< Xm andalso Xm < X+W andalso Y =< Ym andalso Ym < Y+H) -> true; + true -> false + end + end, + {Res,Xm,Ym,X,Y,W,H} = inside_guard(Xm, Ym, X, Y, W, H), + io:format("~p =< ~p andalso ~p < ~p andalso ~p =< ~p andalso ~p < ~p ==> ~p", + [X,Xm,Xm,X+W,Y,Ym,Ym,Y+H,Res]), + Res. + +inside(Xm, Ym, X, Y, W, H) -> + X =< Xm andalso Xm < X+W andalso Y =< Ym andalso Ym < Y+H. + +inside_guard(Xm, Ym, X, Y, W, H) when X =< Xm andalso Xm < X+W + andalso Y =< Ym andalso Ym < Y+H -> + {true,Xm,Ym,X,Y,W,H}; +inside_guard(Xm, Ym, X, Y, W, H) -> + {false,Xm,Ym,X,Y,W,H}. + +overlap(Config) when is_list(Config) -> + ?line true = overlap(7.0, 2.0, 8.0, 0.5), + ?line true = overlap(7.0, 2.0, 8.0, 2.5), + ?line true = overlap(7.0, 2.0, 5.3, 2), + ?line true = overlap(7.0, 2.0, 0.0, 100.0), + + ?line false = overlap(-1, 2, -35, 0.5), + ?line false = overlap(-1, 2, 777, 0.5), + ?line false = overlap(-1, 2, 2, 10), + ?line false = overlap(2, 10, 12, 55.3), + ok. + +overlap(Pos1, Len1, Pos2, Len2) -> + Res = case Pos1 of + Pos1 when (Pos2 =< Pos1 andalso Pos1 < Pos2+Len2) + orelse (Pos1 =< Pos2 andalso Pos2 < Pos1+Len1) -> + true; + Pos1 -> false + end, + Res = (Pos2 =< Pos1 andalso Pos1 < Pos2+Len2) + orelse (Pos1 =< Pos2 andalso Pos2 < Pos1+Len1), + Res = case Pos1 of + Pos1 when (Pos2 =< Pos1 andalso Pos1 < Pos2+Len2) + orelse (Pos1 =< Pos2 andalso Pos2 < Pos1+Len1) -> + true; + Pos1 -> false + end, + id(Res). + + +-define(COMB(A,B,C), (A andalso B orelse C)). + +combined(Config) when is_list(Config) -> + ?line false = comb(false, false, false), + ?line true = comb(false, false, true), + ?line false = comb(false, true, false), + ?line true = comb(false, true, true), + + ?line false = comb(true, false, false), + ?line true = comb(true, true, false), + ?line true = comb(true, false, true), + ?line true = comb(true, true, true), + + ?line false = comb(false, blurf, false), + ?line true = comb(false, blurf, true), + ?line true = comb(true, true, blurf), + + ?line false = ?COMB(false, false, false), + ?line true = ?COMB(false, false, true), + ?line false = ?COMB(false, true, false), + ?line true = ?COMB(false, true, true), + + ?line false = ?COMB(true, false, false), + ?line true = ?COMB(true, true, false), + ?line true = ?COMB(true, false, true), + ?line true = ?COMB(true, true, true), + + ?line false = ?COMB(false, blurf, false), + ?line true = ?COMB(false, blurf, true), + ?line true = ?COMB(true, true, blurf), + + ok. +-undef(COMB). + +comb(A, B, C) -> + Res = A andalso B orelse C, + Res = if + A andalso B orelse C -> true; + true -> false + end, + NotRes = if + not(A andalso B orelse C) -> true; + true -> false + end, + NotRes = id(not Res), + Res = A andalso B orelse C, + Res = if + A andalso B orelse C -> true; + true -> false + end, + NotRes = id(not Res), + Res = if + A andalso B orelse C -> true; + true -> false + end, + id(Res). + +%% Test that a boolean expression in a case expression is properly +%% optimized (in particular, that the error behaviour is correct). +in_case(Config) when is_list(Config) -> + ?line edge_rings = in_case_1(1, 1, 1, 1, 1), + ?line not_loop = in_case_1(0.5, 1, 1, 1, 1), + ?line loop = in_case_1(0.5, 0.9, 1.1, 1, 4), + ?line {'EXIT',{badarith,_}} = (catch in_case_1(1, 1, 1, 1, 0)), + ?line {'EXIT',{badarith,_}} = (catch in_case_1(1, 1, 1, 1, nan)), + ?line {'EXIT',{badarg,_}} = (catch in_case_1(1, 1, 1, blurf, 1)), + ?line {'EXIT',{badarith,_}} = (catch in_case_1([nan], 1, 1, 1, 1)), + ok. + +in_case_1(LenUp, LenDw, LenN, Rotation, Count) -> + Res = in_case_1_body(LenUp, LenDw, LenN, Rotation, Count), + Res = in_case_1_guard(LenUp, LenDw, LenN, Rotation, Count), + Res. + +in_case_1_body(LenUp, LenDw, LenN, Rotation, Count) -> + case (LenUp/Count > 0.707) and (LenN/Count > 0.707) and + (abs(Rotation) > 0.707) of + true -> + edge_rings; + false -> + case (LenUp >= 1) or (LenDw >= 1) or + (LenN =< 1) or (Count < 4) of + true -> + not_loop; + false -> + loop + end + end. + +in_case_1_guard(LenUp, LenDw, LenN, Rotation, Count) -> + case (LenUp/Count > 0.707) andalso (LenN/Count > 0.707) andalso + (abs(Rotation) > 0.707) of + true -> edge_rings; + false when LenUp >= 1 orelse LenDw >= 1 orelse + LenN =< 1 orelse Count < 4 -> not_loop; + false -> loop + end. + +check(V1, V0) -> + if V1 /= V0 -> + io:fwrite("error: ~w.\n", [V1]), + ?t:fail(); + true -> + io:fwrite("ok: ~w.\n", [V1]) + end. + +echo(X) -> + io:fwrite("eval(~w); ",[X]), + X. + +id(I) -> I. diff --git a/lib/debugger/test/bs_bincomp_SUITE.erl b/lib/debugger/test/bs_bincomp_SUITE.erl new file mode 100644 index 0000000000..8ca2b36f1c --- /dev/null +++ b/lib/debugger/test/bs_bincomp_SUITE.erl @@ -0,0 +1,106 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Originally based on Per Gustafsson's test suite. +%% + +-module(bs_bincomp_SUITE). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2, + byte_aligned/1,bit_aligned/1,extended_byte_aligned/1, + extended_bit_aligned/1,mixed/1]). + +-include("test_server.hrl"). + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +all(suite) -> + [byte_aligned,bit_aligned,extended_byte_aligned, + extended_bit_aligned,mixed]. + + +byte_aligned(Config) when is_list(Config) -> + ?line <<"abcdefg">> = << <<(X+32)>> || <<X>> <= <<"ABCDEFG">> >>, + ?line <<1:32/little,2:32/little,3:32/little,4:32/little>> = + << <<X:32/little>> || <<X:32>> <= <<1:32,2:32,3:32,4:32>> >>, + ?line <<1:32/little,2:32/little,3:32/little,4:32/little>> = + << <<X:32/little>> || <<X:16>> <= <<1:16,2:16,3:16,4:16>> >>, + ok. + +bit_aligned(Config) when is_list(Config) -> + ?line <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> = + << <<(X+32):7>> || <<X>> <= <<"ABCDEFG">> >>, + ?line <<"ABCDEFG">> = + << <<(X-32)>> || <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> >>, + ?line <<1:31/little,2:31/little,3:31/little,4:31/little>> = + << <<X:31/little>> || <<X:31>> <= <<1:31,2:31,3:31,4:31>> >>, + ?line <<1:31/little,2:31/little,3:31/little,4:31/little>> = + << <<X:31/little>> || <<X:15>> <= <<1:15,2:15,3:15,4:15>> >>, + ok. + +extended_byte_aligned(Config) when is_list(Config) -> + ?line <<"abcdefg">> = << <<(X+32)>> || X <- "ABCDEFG" >>, + ?line "abcdefg" = [(X+32) || <<X>> <= <<"ABCDEFG">>], + ?line <<1:32/little,2:32/little,3:32/little,4:32/little>> = + << <<X:32/little>> || X <- [1,2,3,4] >>, + ?line [256,512,768,1024] = + [X || <<X:16/little>> <= <<1:16,2:16,3:16,4:16>>], + ok. + +extended_bit_aligned(Config) when is_list(Config) -> + ?line <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>> = + << <<(X+32):7>> || X <- "ABCDEFG" >>, + ?line "ABCDEFG" = [(X-32) || <<X:7>> <= <<$a:7,$b:7,$c:7,$d:7,$e:7,$f:7,$g:7>>], + ?line <<1:31/little,2:31/little,3:31/little,4:31/little>> = + << <<X:31/little>> || X <- [1,2,3,4] >>, + ?line [256,512,768,1024] = + [X || <<X:15/little>> <= <<1:15,2:15,3:15,4:15>>], + ok. + +mixed(Config) when is_list(Config) -> + ?line <<2,3,3,4,4,5,5,6>> = + << <<(X+Y)>> || <<X>> <= <<1,2,3,4>>, <<Y>> <= <<1,2>> >>, + ?line <<2,3,3,4,4,5,5,6>> = + << <<(X+Y)>> || <<X>> <= <<1,2,3,4>>, Y <- [1,2] >>, + ?line <<2,3,3,4,4,5,5,6>> = + << <<(X+Y)>> || X <- [1,2,3,4], Y <- [1,2] >>, + ?line [2,3,3,4,4,5,5,6] = + [(X+Y) || <<X>> <= <<1,2,3,4>>, <<Y>> <= <<1,2>>], + ?line [2,3,3,4,4,5,5,6] = + [(X+Y) || <<X>> <= <<1,2,3,4>>, Y <- [1,2]], + ?line <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> = + << <<(X+Y):3>> || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, <<Y:3>> <= <<1:3,2:3>> >>, + ?line <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> = + << <<(X+Y):3>> || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, Y <- [1,2] >>, + ?line <<2:3,3:3,3:3,4:3,4:3,5:3,5:3,6:3>> = + << <<(X+Y):3>> || X <- [1,2,3,4], Y <- [1,2] >>, + ?line [2,3,3,4,4,5,5,6] = + [(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, <<Y:3>> <= <<1:3,2:3>>], + ?line [2,3,3,4,4,5,5,6] = + [(X+Y) || <<X:3>> <= <<1:3,2:3,3:3,4:3>>, Y <- [1,2]], + ok. diff --git a/lib/debugger/test/bs_construct_SUITE.erl b/lib/debugger/test/bs_construct_SUITE.erl new file mode 100644 index 0000000000..efc125c582 --- /dev/null +++ b/lib/debugger/test/bs_construct_SUITE.erl @@ -0,0 +1,432 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(bs_construct_SUITE). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + test1/1, test2/1, test3/1, test4/1, test5/1, testf/1, not_used/1, in_guard/1, + coerce_to_float/1]). + +-include("test_server.hrl"). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [test1, test2, test3, test4, test5, testf, + not_used, in_guard, coerce_to_float]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +big(1) -> + 57285702734876389752897683. + +i(X) -> X. + +r(L) -> + lists:reverse(L). + +-define(T(B, L), {B, ??B, L}). +-define(N(B), {B, ??B, unknown}). + +-define(FAIL(Expr), ?line {'EXIT',{badarg,_}} = (catch Expr)). + +l(I_13, I_big1) -> + [ + ?T(<<-43>>, + [256-43]), + ?T(<<56>>, + [56]), + ?T(<<1,2>>, + [1, 2]), + ?T(<<4:4, 7:4>>, + [4*16+7]), + ?T(<<777:16/big>>, + [3, 9]), + ?T(<<777:16/little>>, + [9, 3]), + ?T(<<0.0:32/float>>, + [0,0,0,0]), + ?T(<<0.125:32/float>>, + [62,0,0,0]), + ?T(<<0.125:32/little-float>>, + [0,0,0,62]), + ?T(<<I_big1:32>>, + [138, 99, 0, 147]), + ?T(<<57285702734876389752897684:32>>, + [138, 99, 0, 148]), + ?T(<<I_big1:32/little>>, + r([138, 99, 0, 147])), + ?T(<<-1:17/unit:8>>, + lists:duplicate(17, 255)), + + ?T(<<I_13>>, + [13]), + + ?T(<<4:8/unit:2,5:2/unit:8>>, + [0, 4, 0, 5]), + + ?T(<<1:1, 0:6, 1:1>>, + [129]), + ?T(<<1:1/little, 0:6/little, 1:1/little>>, + [129]), + + ?T(<<<<1,2>>/binary>>, + [1, 2]), + ?T(<<<<1,2>>:1/binary>>, + [1]), + ?T(<<4,3,<<1,2>>:1/binary>>, + [4,3,1]), + + ?T(<<(256*45+47)>>, + [47]), + + ?T(<<57:0>>, + []), + + ?T(<<"apa">>, + "apa"), + + ?T(<<1:3,"string",9:5>>, + [46,110,142,77,45,204,233]), + + ?T(<<>>, + []), + + ?T(<<37.98:64/native-float>>, + native_3798()), + + ?T(<<32978297842987249827298387697777669766334937:128/native-integer>>, + native_bignum()) + + ]. + +native_3798() -> + case <<1:16/native>> of + <<0,1>> -> [64,66,253,112,163,215,10,61]; + <<1,0>> -> [61,10,215,163,112,253,66,64] + end. + +native_bignum() -> + case <<1:16/native>> of + <<0,1>> -> [129,205,18,177,1,213,170,101,39,231,109,128,176,11,73,217]; + <<1,0>> -> [217,73,11,176,128,109,231,39,101,170,213,1,177,18,205,129] + end. + +evaluate(Str, Vars) -> + {ok,Tokens,_} = + erl_scan:string(Str ++ " . "), + {ok, [Expr]} = erl_parse:parse_exprs(Tokens), + case erl_eval:expr(Expr, Vars) of + {value, Result, _} -> + Result + end. + +eval_list([], _Vars) -> + []; +eval_list([{C_bin, Str, Bytes} | Rest], Vars) -> + case catch evaluate(Str, Vars) of + {'EXIT', Error} -> + io:format("Evaluation error: ~p, ~p, ~p~n", [Str, Vars, Error]), + exit(Error); + E_bin -> + [{C_bin, E_bin, Str, Bytes} | eval_list(Rest, Vars)] + end. + +one_test({C_bin, E_bin, Str, Bytes}) when list(Bytes) -> + io:format(" ~s, ~p~n", [Str, Bytes]), + Bin = list_to_binary(Bytes), + if + C_bin == Bin -> + ok; + true -> + io:format("ERROR: Compiled: ~p. Expected ~p. Got ~p.~n", + [Str, Bytes, binary_to_list(C_bin)]), + test_server:fail(comp) + end, + if + E_bin == Bin -> + ok; + true -> + io:format("ERROR: Interpreted: ~p. Expected ~p. Got ~p.~n", + [Str, Bytes, binary_to_list(E_bin)]), + test_server:fail(comp) + end; +one_test({C_bin, E_bin, Str, Result}) -> + io:format(" ~s ~p~n", [Str, C_bin]), + if + C_bin == E_bin -> + ok; + true -> + Arbitrary = case Result of + unknown -> + size(C_bin); + _ -> + Result + end, + case equal_lists(binary_to_list(C_bin), + binary_to_list(E_bin), + Arbitrary) of + false -> + io:format("ERROR: Compiled not equal to interpreted:" + "~n ~p, ~p.~n", + [binary_to_list(C_bin), binary_to_list(E_bin)]), + test_server:fail(comp); + 0 -> + ok; + %% For situations where the final bits may not matter, like + %% for floats: + N when integer(N) -> + io:format("Info: compiled and interpreted differ in the" + " last bytes:~n ~p, ~p.~n", + [binary_to_list(C_bin), binary_to_list(E_bin)]), + ok + end + end. + +equal_lists([], [], _) -> + 0; +equal_lists([], _, _) -> + false; +equal_lists(_, [], _) -> + false; +equal_lists([A|AR], [A|BR], R) -> + equal_lists(AR, BR, R); +equal_lists(A, B, R) -> + if + length(A) /= length(B) -> + false; + length(A) =< R -> + R; + true -> + false + end. + +%%% Simple working cases +test1(suite) -> []; +test1(Config) when list(Config) -> + ?line I_13 = i(13), + ?line I_big1 = big(1), + ?line Vars = [{'I_13', I_13}, + {'I_big1', I_big1}], + ?line lists:foreach(fun one_test/1, eval_list(l(I_13, I_big1), Vars)). + +%%% Misc + +%%% <<A:S, A:(N-S)>> +comp(N, A, S) -> + M1 = (1 bsl S) - 1, + M2 = (1 bsl (N-S)) - 1, + [((A band M1) bsl (N-S)) bor (A band M2)]. + +gen(N, S, A) -> + [?T(<<A:S, A:(N-S)>>, comp(N, A, S))]. + +gen_l(N, S, A) -> + [?T(<<A:S/little, A:(N-S)/little>>, comp(N, A, S))]. + +test2(suite) -> []; +test2(Config) when list(Config) -> + ?line test2(0, 8, 2#10101010101010101), + ?line test2(0, 8, 2#1111111111). + +test2(End, End, _) -> + ok; +test2(I, End, A) -> + test2(I, A), + test2(I+1, End, A). + +test2(S, A) -> + N = 8, + Vars = [{'A',A}, {'N',N}, {'S',S}], + io:format("Vars: ~p\n", [Vars]), + lists:foreach(fun one_test/1, eval_list(gen(N, S, A), Vars)), + lists:foreach(fun one_test/1, eval_list(gen_l(N, S, A), Vars)). + +%%% Tests without facit + +t3() -> + [?N(<<4711:13, 9876:13, 3:6>>), + ?N(<<4.57:64/float>>), + ?N(<<4.57:32/float>>), + + ?N(<<>>) + ]. + +test3(suite) -> []; +test3(Config) when list(Config) -> + ?line Vars = [], + ?line lists:foreach(fun one_test/1, eval_list(t3(), Vars)). + +gen_u(N, S, A) -> + [?N(<<A:S, A:(N-S)>>)]. + +gen_u_l(N, S, A) -> + [?N(<<A:S/little, A:(N-S)/little>>)]. + +test4(suite) -> []; +test4(Config) when list(Config) -> + ?line test4(0, 16, 2#10101010101010101), + ?line test4(0, 16, 2#1111111111). + +test4(End, End, _) -> + ok; +test4(I, End, A) -> + test4(I, A), + test4(I+1, End, A). + +test4(S, A) -> + N = 16, + Vars = [{'A', A}, {'N', 16}, {'S', S}], + lists:foreach(fun one_test/1, eval_list(gen_u(N, S, A), Vars)), + lists:foreach(fun one_test/1, eval_list(gen_u_l(N, S, A), Vars)). + +gen_b(N, S, A) -> + [?T(<<A:S/binary-unit:1, A:(N-S)/binary-unit:1>>, + binary_to_list(<<A:S/binary-unit:1, A:(N-S)/binary-unit:1>>))]. + +test5(suite) -> []; +test5(doc) -> ["OTP-3995"]; +test5(Config) when list(Config) -> + ?line test5(0, 8, <<73>>), + ?line test5(0, 8, <<68>>). + +test5(End, End, _) -> + ok; +test5(I, End, A) -> + test5(I, A), + test5(I+1, End, A). + +test5(S, A) -> + N = 8, + Vars = [{'A', A}, {'N', 8}, {'S', S}], + lists:foreach(fun one_test/1, eval_list(gen_b(N, S, A), Vars)). + +%%% Failure cases +testf(suite) -> []; +testf(Config) when list(Config) -> + ?FAIL(<<3.14>>), + ?FAIL(<<<<1,2>>>>), + + ?FAIL(<<2.71/binary>>), + ?FAIL(<<24334/binary>>), + ?FAIL(<<24334344294788947129487129487219847/binary>>), + + ?FAIL(<<<<1,2,3>>/float>>), + + %% Negative field widths. + testf_1(-8, <<1,2,3,4,5>>), + + ?FAIL(<<42:(-16)>>), + ?FAIL(<<3.14:(-8)/float>>), + ?FAIL(<<<<23,56,0,2>>:(-16)/binary>>), + ?FAIL(<<<<23,56,0,2>>:(2.5)/binary>>), + ?FAIL(<<<<23,56,0,2>>:(anka)>>), + + ok. + +testf_1(W, B) -> + ?FAIL(<<42:W>>), + ?FAIL(<<3.14:W/float>>), + ?FAIL(<<B:W/binary>>). + +not_used(doc) -> + "Test that constructed binaries that are not used will still give an exception."; +not_used(Config) when is_list(Config) -> + ?line ok = not_used1(3, <<"dum">>), + ?line ?FAIL(not_used1(3, "dum")), + ?line ?FAIL(not_used2(444, -2)), + ?line ?FAIL(not_used2(444, anka)), + ?line ?FAIL(not_used3(444)), + ok. + +not_used1(I, BinString) -> + <<I:32,BinString/binary>>, + ok. + +not_used2(I, Sz) -> + <<I:Sz>>, + ok. + +not_used3(I) -> + <<I:(-8)>>, + ok. + +in_guard(Config) when list(Config) -> + ?line 1 = in_guard(<<16#74ad:16>>, 16#e95, 5), + ?line 2 = in_guard(<<16#3A,16#F7,"hello">>, 16#3AF7, <<"hello">>), + ?line 3 = in_guard(<<16#FBCD:14,3.1415/float,3:2>>, 16#FBCD, 3.1415), + nope = in_guard(<<1>>, 42, b), + nope = in_guard(<<1>>, a, b), + nope = in_guard(<<1,2>>, 1, 1), + nope = in_guard(<<4,5>>, 1, 2.71), + nope = in_guard(<<4,5>>, 1, <<12,13>>), + ok. + +in_guard(Bin, A, B) when <<A:13,B:3>> == Bin -> 1; +in_guard(Bin, A, B) when <<A:16,B/binary>> == Bin -> 2; +in_guard(Bin, A, B) when <<A:14,B/float,3:2>> == Bin -> 3; +in_guard(Bin, A, B) when {a,b,<<A:14,B/float,3:2>>} == Bin -> cant_happen; +in_guard(_, _, _) -> nope. + +-define(COF(Int0), + ?line (fun(Int) -> + true = <<Int:32/float>> =:= <<(float(Int)):32/float>>, + true = <<Int:64/float>> =:= <<(float(Int)):64/float>> + end)(nonliteral(Int0)), + ?line true = <<Int0:32/float>> =:= <<(float(Int0)):32/float>>, + ?line true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>). + +-define(COF64(Int0), + ?line (fun(Int) -> + true = <<Int:64/float>> =:= <<(float(Int)):64/float>> + end)(nonliteral(Int0)), + ?line true = <<Int0:64/float>> =:= <<(float(Int0)):64/float>>). + +nonliteral(X) -> X. + +coerce_to_float(Config) when list(Config) -> + ?COF(0), + ?COF(-1), + ?COF(1), + ?COF(42), + ?COF(255), + ?COF(-255), + ?COF(38474), + ?COF(387498738948729893849444444443), + ?COF(-37489378937773899999999999999993), + ?COF64(298748888888888888888888888883478264866528467367364766666666666666663), + ?COF64(-367546729879999999999947826486652846736736476555566666663), + ok. diff --git a/lib/debugger/test/bs_match_bin_SUITE.erl b/lib/debugger/test/bs_match_bin_SUITE.erl new file mode 100644 index 0000000000..3966dc41ef --- /dev/null +++ b/lib/debugger/test/bs_match_bin_SUITE.erl @@ -0,0 +1,114 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + + +-module(bs_match_bin_SUITE). + +-author('bjorn@erix.ericsson.se'). +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + byte_split_binary/1,bit_split_binary/1]). + +-include("test_server.hrl"). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [byte_split_binary,bit_split_binary]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +byte_split_binary(doc) -> "Tries to split a binary at all byte-aligned positions."; +byte_split_binary(suite) -> []; +byte_split_binary(Config) when list(Config) -> + ?line L = lists:seq(0, 57), + ?line B = mkbin(L), + ?line byte_split(L, B, size(B)). + +byte_split(L, B, Pos) when Pos >= 0 -> + ?line Sz1 = Pos, + ?line Sz2 = size(B) - Pos, + ?line <<B1:Sz1/binary,B2:Sz2/binary>> = B, + ?line B1 = list_to_binary(lists:sublist(L, 1, Pos)), + ?line B2 = list_to_binary(lists:nthtail(Pos, L)), + ?line byte_split(L, B, Pos-1); +byte_split(_L, _B, _) -> ok. + +bit_split_binary(doc) -> "Tries to split a binary at all positions."; +bit_split_binary(suite) -> []; +bit_split_binary(Config) when list(Config) -> + Fun = fun(Bin, List, SkipBef, N) -> + ?line SkipAft = 8*size(Bin) - N - SkipBef, + io:format("~p, ~p, ~p", [SkipBef,N,SkipAft]), + ?line <<_I1:SkipBef,OutBin:N/binary-unit:1,_I2:SkipAft>> = Bin, + ?line OutBin = make_bin_from_list(List, N) + end, + ?line bit_split_binary1(Fun, erlang:md5(<<1,2,3>>)), + ok. + +bit_split_binary1(Action, Bin) -> + BitList = bits_to_list(binary_to_list(Bin), 16#80), + bit_split_binary2(Action, Bin, BitList, 0). + +bit_split_binary2(Action, Bin, [_|T]=List, Bef) -> + bit_split_binary3(Action, Bin, List, Bef, size(Bin)*8), + bit_split_binary2(Action, Bin, T, Bef+1); +bit_split_binary2(_Action, _Bin, [], _Bef) -> ok. + +bit_split_binary3(Action, Bin, List, Bef, Aft) when Bef =< Aft -> + Action(Bin, List, Bef, (Aft-Bef) div 8 * 8), + bit_split_binary3(Action, Bin, List, Bef, Aft-8); +bit_split_binary3(_, _, _, _, _) -> ok. + +make_bin_from_list(_List, 0) -> + mkbin([]); +make_bin_from_list(List, N) -> + list_to_binary([make_int(List, 8, 0), + make_bin_from_list(lists:nthtail(8, List), N-8)]). + + +make_int(_List, 0, Acc) -> Acc; +make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H). + +bits_to_list([_H|T], 0) -> bits_to_list(T, 16#80); +bits_to_list([H|_]=List, Mask) -> + [case H band Mask of + 0 -> 0; + _ -> 1 + end|bits_to_list(List, Mask bsr 1)]; +bits_to_list([], _) -> []. + + +mkbin(L) when list(L) -> list_to_binary(L). diff --git a/lib/debugger/test/bs_match_int_SUITE.erl b/lib/debugger/test/bs_match_int_SUITE.erl new file mode 100644 index 0000000000..1159ac9ef8 --- /dev/null +++ b/lib/debugger/test/bs_match_int_SUITE.erl @@ -0,0 +1,230 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(bs_match_int_SUITE). + +-author('bjorn@erix.ericsson.se'). +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + integer/1,signed_integer/1,dynamic/1,more_dynamic/1,mml/1]). + +-include("test_server.hrl"). + +-import(lists, [seq/2]). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [integer,signed_integer,dynamic,more_dynamic,mml]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(4)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +integer(suite) -> []; +integer(Config) when list(Config) -> + ?line 0 = get_int(mkbin([])), + ?line 0 = get_int(mkbin([0])), + ?line 42 = get_int(mkbin([42])), + ?line 255 = get_int(mkbin([255])), + ?line 256 = get_int(mkbin([1,0])), + ?line 257 = get_int(mkbin([1,1])), + ?line 258 = get_int(mkbin([1,2])), + ?line 258 = get_int(mkbin([1,2])), + ?line 65534 = get_int(mkbin([255,254])), + ?line 16776455 = get_int(mkbin([255,253,7])), + ?line 4245492555 = get_int(mkbin([253,13,19,75])), + ?line Eight = [200,1,19,128,222,42,97,111], + ?line cmp128(Eight, uint(Eight)), + ?line fun_clause(catch get_int(mkbin(seq(1,5)))), + ok. + +get_int(<<I:0>>) -> I; +get_int(<<I:8>>) -> I; +get_int(<<I:16>>) -> I; +get_int(<<I:24>>) -> I; +get_int(<<I:32>>) -> I. + +cmp128(<<I:128>>, I) -> equal; +cmp128(_B, _I) -> not_equal. + +signed_integer(suite) -> []; +signed_integer(Config) when list(Config) -> + ?line {no_match,_} = sint(mkbin([])), + ?line {no_match,_} = sint(mkbin([1,2,3])), + ?line 127 = sint(mkbin([127])), + ?line -1 = sint(mkbin([255])), + ?line -128 = sint(mkbin([128])), + ?line 42 = sint(mkbin([42,255])), + ?line 127 = sint(mkbin([127,255])). + +sint(Bin) -> + case Bin of + <<I:8/signed>> -> I; + <<I:8/signed,_:3,_:5>> -> I; + Other -> {no_match,Other} + end. + +uint(L) -> uint(L, 0). +uint([H|T], Acc) -> uint(T, Acc bsl 8 bor H); +uint([], Acc) -> Acc. + +dynamic(Config) when list(Config) -> + dynamic(mkbin([255]), 8), + dynamic(mkbin([255,255]), 16), + dynamic(mkbin([255,255,255]), 24), + dynamic(mkbin([255,255,255,255]), 32), + ok. + +dynamic(Bin, S1) when S1 >= 0 -> + S2 = size(Bin) * 8 - S1, + dynamic(Bin, S1, S2, (1 bsl S1) - 1, (1 bsl S2) - 1), + dynamic(Bin, S1-1); +dynamic(_Bin, _) -> ok. + +dynamic(Bin, S1, S2, A, B) -> +% io:format("~p ~p ~p ~p\n", [S1,S2,A,B]), + case Bin of + <<A:S1,B:S2>> -> + io:format("~p ~p ~p ~p\n", [S1,S2,A,B]), + ok; + _Other -> + erlang:error(badmatch, [Bin,S1,S2,A,B]) + end. + +more_dynamic(doc) -> "Extract integers at different alignments and of different sizes."; +more_dynamic(Config) when list(Config) -> + + % Unsigned big-endian numbers. + Unsigned = fun(Bin, List, SkipBef, N) -> + SkipAft = 8*size(Bin) - N - SkipBef, + <<_I1:SkipBef,Int:N,_I2:SkipAft>> = Bin, + Int = make_int(List, N, 0) + end, + ?line more_dynamic1(Unsigned, funny_binary(42)), + + % Signed big-endian numbers. + Signed = fun(Bin, List, SkipBef, N) -> + SkipAft = 8*size(Bin) - N - SkipBef, + <<_I1:SkipBef,Int:N/signed,_I2:SkipAft>> = Bin, + case make_signed_int(List, N) of + Int -> ok; + Other -> + io:format("Bin = ~p,", [Bin]), + io:format("SkipBef = ~p, N = ~p", [SkipBef,N]), + io:format("Expected ~p, got ~p", [Int,Other]), + ?t:fail() + end + end, + ?line more_dynamic1(Signed, funny_binary(43)), + + % Unsigned little-endian numbers. + UnsLittle = fun(Bin, List, SkipBef, N) -> + SkipAft = 8*size(Bin) - N - SkipBef, + <<_I1:SkipBef,Int:N/little,_I2:SkipAft>> = Bin, + Int = make_int(big_to_little(List, N), N, 0) + end, + ?line more_dynamic1(UnsLittle, funny_binary(44)), + + % Signed little-endian numbers. + SignLittle = fun(Bin, List, SkipBef, N) -> + SkipAft = 8*size(Bin) - N - SkipBef, + <<_I1:SkipBef,Int:N/signed-little,_I2:SkipAft>> = Bin, + Little = big_to_little(List, N), + Int = make_signed_int(Little, N) + end, + ?line more_dynamic1(SignLittle, funny_binary(45)), + + ok. + +funny_binary(N) -> + B0 = erlang:md5([N]), + {B1,_B2} = split_binary(B0, size(B0) div 2), + B1. + +more_dynamic1(Action, Bin) -> + BitList = bits_to_list(binary_to_list(Bin), 16#80), + more_dynamic2(Action, Bin, BitList, 0). + +more_dynamic2(Action, Bin, [_|T]=List, Bef) -> + more_dynamic3(Action, Bin, List, Bef, size(Bin)*8), + more_dynamic2(Action, Bin, T, Bef+1); +more_dynamic2(_Action, _Bin, [], _Bef) -> ok. + +more_dynamic3(Action, Bin, List, Bef, Aft) when Bef =< Aft -> +%% io:format("~p, ~p", [Bef,Aft-Bef]), + Action(Bin, List, Bef, Aft-Bef), + more_dynamic3(Action, Bin, List, Bef, Aft-1); +more_dynamic3(_, _, _, _, _) -> ok. + +big_to_little(List, N) -> big_to_little(List, N, []). + +big_to_little([B0,B1,B2,B3,B4,B5,B6,B7|T], N, Acc) when N >= 8 -> + big_to_little(T, N-8, [B0,B1,B2,B3,B4,B5,B6,B7|Acc]); +big_to_little(List, N, Acc) -> lists:sublist(List, 1, N) ++ Acc. + +make_signed_int(_List, 0) -> 0; +make_signed_int([0|_T]=List, N) -> make_int(List, N, 0); +make_signed_int([1|_T]=List0, N) -> + List1 = reversed_sublist(List0, N, []), + List2 = two_complement_and_reverse(List1, 1, []), + -make_int(List2, length(List2), 0). + +reversed_sublist(_List, 0, Acc) -> Acc; +reversed_sublist([H|T], N, Acc) -> reversed_sublist(T, N-1, [H|Acc]). + +two_complement_and_reverse([H|T], Carry, Acc) -> + Sum = 1-H+Carry, + two_complement_and_reverse(T, Sum div 2, [Sum rem 2|Acc]); +two_complement_and_reverse([], Carry, Acc) -> [Carry|Acc]. + +make_int(_List, 0, Acc) -> Acc; +make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H). + +bits_to_list([_H|T], 0) -> bits_to_list(T, 16#80); +bits_to_list([H|_]=List, Mask) -> + [case H band Mask of + 0 -> 0; + _ -> 1 + end|bits_to_list(List, Mask bsr 1)]; +bits_to_list([], _) -> []. + +fun_clause({'EXIT',{function_clause,_}}) -> ok. +mkbin(L) when list(L) -> list_to_binary(L). + +mml(Config) when list(Config) -> + ?line single_byte_binary = mml_choose(<<42>>), + ?line multi_byte_binary = mml_choose(<<42,43>>). + +mml_choose(<<_A:8>>) -> single_byte_binary; +mml_choose(<<_A:8, _T/binary>>) -> multi_byte_binary. diff --git a/lib/debugger/test/bs_match_misc_SUITE.erl b/lib/debugger/test/bs_match_misc_SUITE.erl new file mode 100644 index 0000000000..5e1160a8e9 --- /dev/null +++ b/lib/debugger/test/bs_match_misc_SUITE.erl @@ -0,0 +1,152 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(bs_match_misc_SUITE). + +-author('bjorn@erix.ericsson.se'). +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + bound_var/1,bound_tail/1,t_float/1,little_float/1,sean/1]). + +-include("test_server.hrl"). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [bound_var,bound_tail,t_float,little_float,sean]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +bound_var(doc) -> "Test matching of bound variables."; +bound_var(Config) when list(Config) -> + ?line ok = bound_var(42, 13, <<42,13>>), + ?line nope = bound_var(42, 13, <<42,255>>), + ?line nope = bound_var(42, 13, <<154,255>>), + ok. + +bound_var(A, B, <<A:8,B:8>>) -> ok; +bound_var(_, _, _) -> nope. + +bound_tail(doc) -> "Test matching of a bound tail."; +bound_tail(Config) when list(Config) -> + ?line ok = bound_tail(<<>>, <<13,14>>), + ?line ok = bound_tail(<<2,3>>, <<1,1,2,3>>), + ?line nope = bound_tail(<<2,3>>, <<1,1,2,7>>), + ?line nope = bound_tail(<<2,3>>, <<1,1,2,3,4>>), + ?line nope = bound_tail(<<2,3>>, <<>>), + ok. + +bound_tail(T, <<_:16,T/binary>>) -> ok; +bound_tail(_, _) -> nope. + +t_float(Config) when list(Config) -> + F = f1(), + G = f_one(), + + ?line G = match_float(<<63,128,0,0>>, 32, 0), + ?line G = match_float(<<63,240,0,0,0,0,0,0>>, 64, 0), + + ?line fcmp(F, match_float(<<F:32/float>>, 32, 0)), + ?line fcmp(F, match_float(<<F:64/float>>, 64, 0)), + ?line fcmp(F, match_float(<<1:1,F:32/float,127:7>>, 32, 1)), + ?line fcmp(F, match_float(<<1:1,F:64/float,127:7>>, 64, 1)), + ?line fcmp(F, match_float(<<1:13,F:32/float,127:3>>, 32, 13)), + ?line fcmp(F, match_float(<<1:13,F:64/float,127:3>>, 64, 13)), + ok. + + +fcmp(F1, F2) when (F1 - F2) / F2 < 0.0000001 -> ok. + +match_float(Bin0, Fsz, I) -> + Bin = make_sub_bin(Bin0), + Bsz = size(Bin) * 8, + Tsz = Bsz - Fsz - I, + <<_:I,F:Fsz/float,_:Tsz>> = Bin, + F. + +little_float(Config) when list(Config) -> + F = f2(), + G = f_one(), + + ?line G = match_float_little(<<0,0,0,0,0,0,240,63>>, 64, 0), + ?line G = match_float_little(<<0,0,128,63>>, 32, 0), + + ?line fcmp(F, match_float_little(<<F:32/float-little>>, 32, 0)), + ?line fcmp(F, match_float_little(<<F:64/float-little>>, 64, 0)), + ?line fcmp(F, match_float_little(<<1:1,F:32/float-little,127:7>>, 32, 1)), + ?line fcmp(F, match_float_little(<<1:1,F:64/float-little,127:7>>, 64, 1)), + ?line fcmp(F, match_float_little(<<1:13,F:32/float-little,127:3>>, 32, 13)), + ?line fcmp(F, match_float_little(<<1:13,F:64/float-little,127:3>>, 64, 13)), + + ok. + +match_float_little(Bin0, Fsz, I) -> + Bin = make_sub_bin(Bin0), + Bsz = size(Bin) * 8, + Tsz = Bsz - Fsz - I, + <<_:I,F:Fsz/float-little,_:Tsz>> = Bin, + F. + + +make_sub_bin(Bin0) -> + Sz = size(Bin0), + Bin1 = <<37,Bin0/binary,38,39>>, + <<_:8,Bin:Sz/binary,_:8,_:8>> = Bin1, + Bin. + +f1() -> + 3.1415. + +f2() -> + 2.7133. + +f_one() -> + 1.0. + +sean(Config) when list(Config) -> + ?line small = sean1(<<>>), + ?line small = sean1(<<1>>), + ?line small = sean1(<<1,2>>), + ?line small = sean1(<<1,2,3>>), + ?line large = sean1(<<1,2,3,4>>), + + ?line small = sean1(<<4>>), + ?line small = sean1(<<4,5>>), + ?line small = sean1(<<4,5,6>>), + ?line {'EXIT',{function_clause,_}} = (catch sean1(<<4,5,6,7>>)), + ok. + +sean1(<<B/binary>>) when size(B) < 4 -> small; +sean1(<<1, _B/binary>>) -> large. diff --git a/lib/debugger/test/bs_match_tail_SUITE.erl b/lib/debugger/test/bs_match_tail_SUITE.erl new file mode 100644 index 0000000000..7fa16b3c6a --- /dev/null +++ b/lib/debugger/test/bs_match_tail_SUITE.erl @@ -0,0 +1,106 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(bs_match_tail_SUITE). + +-author('bjorn@erix.ericsson.se'). +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + aligned/1,unaligned/1,zero_tail/1]). + +-include("test_server.hrl"). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [aligned,unaligned,zero_tail]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +aligned(doc) -> "Test aligned tails."; +aligned(Config) when list(Config) -> + ?line Tail1 = mkbin([]), + ?line {258,Tail1} = al_get_tail_used(mkbin([1,2])), + ?line Tail2 = mkbin(lists:seq(1, 127)), + ?line {35091,Tail2} = al_get_tail_used(mkbin([137,19|Tail2])), + + ?line 64896 = al_get_tail_unused(mkbin([253,128])), + ?line 64895 = al_get_tail_unused(mkbin([253,127|lists:seq(42, 255)])), + + ?line Tail3 = mkbin(lists:seq(0, 19)), + ?line {0,Tail1} = get_dyn_tail_used(Tail1, 0), + ?line {0,Tail3} = get_dyn_tail_used(mkbin([Tail3]), 0), + ?line {73,Tail3} = get_dyn_tail_used(mkbin([73|Tail3]), 8), + + ?line 0 = get_dyn_tail_unused(mkbin([]), 0), + ?line 233 = get_dyn_tail_unused(mkbin([233]), 8), + ?line 23 = get_dyn_tail_unused(mkbin([23,22,2]), 8), + ok. + +al_get_tail_used(<<A:16,T/binary>>) -> {A,T}. +al_get_tail_unused(<<A:16,_T/binary>>) -> A. + +unaligned(doc) -> "Test that an non-aligned tail cannot be matched out."; +unaligned(Config) when list(Config) -> + ?line {'EXIT',{function_clause,_}} = (catch get_tail_used(mkbin([42]))), + ?line {'EXIT',{{badmatch,_},_}} = (catch get_dyn_tail_used(mkbin([137]), 3)), + ?line {'EXIT',{function_clause,_}} = (catch get_tail_unused(mkbin([42,33]))), + ?line {'EXIT',{{badmatch,_},_}} = (catch get_dyn_tail_unused(mkbin([44]), 7)), + ok. + +get_tail_used(<<A:1,T/binary>>) -> {A,T}. + +get_tail_unused(<<A:15,_/binary>>) -> A. + +get_dyn_tail_used(Bin, Sz) -> + <<A:Sz,T/binary>> = Bin, + {A,T}. + +get_dyn_tail_unused(Bin, Sz) -> + <<A:Sz,_T/binary>> = Bin, + A. + +zero_tail(doc) -> "Test that zero tails are tested correctly."; +zero_tail(Config) when list(Config) -> + ?line 7 = (catch test_zero_tail(mkbin([7]))), + ?line {'EXIT',{function_clause,_}} = (catch test_zero_tail(mkbin([1,2]))), + ?line {'EXIT',{function_clause,_}} = (catch test_zero_tail2(mkbin([1,2,3]))), + ok. + +test_zero_tail(<<A:8>>) -> A. + +test_zero_tail2(<<_A:4,_B:4>>) -> ok. + +mkbin(L) when list(L) -> list_to_binary(L). diff --git a/lib/debugger/test/bs_utf_SUITE.erl b/lib/debugger/test/bs_utf_SUITE.erl new file mode 100644 index 0000000000..3d69d2a101 --- /dev/null +++ b/lib/debugger/test/bs_utf_SUITE.erl @@ -0,0 +1,292 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(bs_utf_SUITE). + +-export([all/1,init_all/1,finish_all/1, + init_per_testcase/2,fin_per_testcase/2, + utf8_roundtrip/1,unused_utf_char/1,utf16_roundtrip/1, + utf32_roundtrip/1,guard/1,extreme_tripping/1]). + +-include("test_server.hrl"). +-compile([no_jopt,time]). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [utf8_roundtrip,unused_utf_char,utf16_roundtrip, + utf32_roundtrip,guard,extreme_tripping]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +utf8_roundtrip(Config) when is_list(Config) -> + ?line [utf8_roundtrip_1(P) || P <- utf_data()], + ok. + +utf8_roundtrip_1({Str,Bin,Bin}) -> + ?line Str = utf8_to_list(Bin), + ?line Bin = list_to_utf8(Str), + ?line [ok = utf8_guard(C, <<42,C/utf8>>) || C <- Str], + ?line [error = utf8_guard(C, <<C/utf8>>) || C <- Str], + ok. + +utf8_guard(C, Bin) when <<42,C/utf8>> =:= Bin -> ok; +utf8_guard(_, _) -> error. + +utf8_to_list(<<C/utf8,T/binary>>) -> + [C|utf8_to_list(T)]; +utf8_to_list(<<>>) -> []. + +list_to_utf8(L) -> + list_to_utf8(L, <<>>). + +list_to_utf8([H|T], Bin) -> + list_to_utf8(T, <<Bin/binary,H/utf8>>); +list_to_utf8([], Bin) -> Bin. + +unused_utf_char(Config) when is_list(Config) -> + [true = utf8_len(Utf8) =:= length(Str) || + {Str,Utf8} <- utf_data()], + ok. + +utf8_len(B) -> + utf8_len(B, 0). + +utf8_len(<<_/utf8,T/binary>>, N) -> + utf8_len(T, N+1); +utf8_len(<<>>, N) -> N. + +utf16_roundtrip(Config) when is_list(Config) -> + ?line {Str,Big,Big,Little,Little} = utf16_data(), + ?line 4 = utf16_big_len(Big), + ?line 4 = utf16_little_len(Little), + ?line Str = big_utf16_to_list(Big), + ?line Str = little_utf16_to_list(Little), + + ?line Big = list_to_big_utf16(Str), + ?line Little = list_to_little_utf16(Str), + + ok. + +utf16_big_len(B) -> + utf16_big_len(B, 0). + +utf16_big_len(<<_/utf16,T/binary>>, N) -> + utf16_big_len(T, N+1); +utf16_big_len(<<>>, N) -> N. + +utf16_little_len(B) -> + utf16_little_len(B, 0). + +utf16_little_len(<<_/little-utf16,T/binary>>, N) -> + utf16_little_len(T, N+1); +utf16_little_len(<<>>, N) -> N. + +list_to_big_utf16(List) -> + list_to_big_utf16(List, <<>>). + +list_to_big_utf16([H|T], Bin) -> + list_to_big_utf16(T, <<Bin/binary,H/utf16>>); +list_to_big_utf16([], Bin) -> Bin. + +list_to_little_utf16(List) -> + list_to_little_utf16(List, <<>>). + +list_to_little_utf16([H|T], Bin) -> + list_to_little_utf16(T, <<Bin/binary,H/little-utf16>>); +list_to_little_utf16([], Bin) -> Bin. + +big_utf16_to_list(<<H/utf16,T/binary>>) -> + [H|big_utf16_to_list(T)]; +big_utf16_to_list(<<>>) -> []. + +little_utf16_to_list(<<H/little-utf16,T/binary>>) -> + [H|little_utf16_to_list(T)]; +little_utf16_to_list(<<>>) -> []. + +utf32_roundtrip(Config) when is_list(Config) -> + ?line {Str,Big,Big,Little,Little} = utf32_data(), + ?line 4 = utf32_big_len(Big), + ?line 4 = utf32_little_len(Little), + ?line Str = big_utf32_to_list(Big), + ?line Str = little_utf32_to_list(Little), + + ?line Big = list_to_big_utf32(Str), + ?line Little = list_to_little_utf32(Str), + + ok. + +utf32_big_len(B) -> + utf32_big_len(B, 0). + +utf32_big_len(<<_/utf32,T/binary>>, N) -> + utf32_big_len(T, N+1); +utf32_big_len(<<>>, N) -> N. + +utf32_little_len(B) -> + utf32_little_len(B, 0). + +utf32_little_len(<<_/little-utf32,T/binary>>, N) -> + utf32_little_len(T, N+1); +utf32_little_len(<<>>, N) -> N. + +list_to_big_utf32(List) -> + list_to_big_utf32(List, <<>>). + +list_to_big_utf32([H|T], Bin) -> + list_to_big_utf32(T, <<Bin/binary,H/utf32>>); +list_to_big_utf32([], Bin) -> Bin. + +list_to_little_utf32(List) -> + list_to_little_utf32(List, <<>>). + +list_to_little_utf32([H|T], Bin) -> + list_to_little_utf32(T, <<Bin/binary,H/little-utf32>>); +list_to_little_utf32([], Bin) -> Bin. + +big_utf32_to_list(<<H/utf32,T/binary>>) -> + [H|big_utf32_to_list(T)]; +big_utf32_to_list(<<>>) -> []. + +little_utf32_to_list(<<H/little-utf32,T/binary>>) -> + [H|little_utf32_to_list(T)]; +little_utf32_to_list(<<>>) -> []. + + +guard(Config) when is_list(Config) -> + ?line error = do_guard(16#D800), + ok. + +do_guard(C) when byte_size(<<C/utf8>>) =/= 42 -> ok; +do_guard(C) when byte_size(<<C/utf16>>) =/= 42 -> ok; +do_guard(C) when byte_size(<<C/utf32>>) =/= 42 -> ok; +do_guard(_) -> error. + +%% The purpose of this test is to make sure that +%% the delayed creation of sub-binaries works. + +extreme_tripping(Config) when is_list(Config) -> + ?line Unicode = lists:seq(0, 1024), + ?line Utf8 = unicode_to_utf8(Unicode, <<>>), + ?line Utf16 = utf8_to_utf16(Utf8, <<>>), + ?line Utf32 = utf8_to_utf32(Utf8, <<>>), + ?line Utf32 = utf16_to_utf32(Utf16, <<>>), + ?line Utf8 = utf32_to_utf8(Utf32, <<>>), + ?line Unicode = utf32_to_unicode(Utf32), + ok. + +unicode_to_utf8([C|T], Bin) -> + unicode_to_utf8(T, <<Bin/bytes,C/utf8>>); +unicode_to_utf8([], Bin) -> Bin. + +utf8_to_utf16(<<C/utf8,T/binary>>, Bin) -> + utf8_to_utf16(T, <<Bin/bytes,C/utf16>>); +utf8_to_utf16(<<>>, Bin) -> Bin. + +utf16_to_utf32(<<C/utf16,T/binary>>, Bin) -> + utf16_to_utf32(T, <<Bin/bytes,C/utf32>>); +utf16_to_utf32(<<>>, Bin) -> Bin. + +utf8_to_utf32(<<C/utf8,T/binary>>, Bin) -> + utf8_to_utf32(T, <<Bin/bytes,C/utf32>>); +utf8_to_utf32(<<>>, Bin) -> Bin. + +utf32_to_utf8(<<C/utf32,T/binary>>, Bin) -> + utf32_to_utf8(T, <<Bin/bytes,C/utf8>>); +utf32_to_utf8(<<>>, Bin) -> Bin. + +utf32_to_unicode(<<C/utf32,T/binary>>) -> + [C|utf32_to_unicode(T)]; +utf32_to_unicode(<<>>) -> []. + +utf_data() -> +%% From RFC-3629. + + %% Give the compiler a change to do some constant propagation. + NotIdentical = 16#2262, + + [ + %% "A<NOT IDENTICAL TO><ALPHA>." + {[16#0041,NotIdentical,16#0391,16#002E], + <<16#0041/utf8,NotIdentical/utf8,16#0391/utf8,16#002E/utf8>>, + <<16#41,16#E2,16#89,16#A2,16#CE,16#91,16#2E>>}, + + %% Korean "hangugeo" (meaning "the Korean language") + {[16#D55C,16#AD6D,16#C5B4], + <<16#D55C/utf8,16#AD6D/utf8,16#C5B4/utf8>>, + <<16#ED,16#95,16#9C,16#EA,16#B5,16#AD,16#EC,16#96,16#B4>>}, + + %% Japanese "nihongo" (meaning "the Japanese language"). + {[16#65E5,16#672C,16#8A9E], + <<16#65E5/utf8,16#672C/utf8,16#8A9E/utf8>>, + <<16#E6,16#97,16#A5,16#E6,16#9C,16#AC,16#E8,16#AA,16#9E>>} + ]. + +utf16_data() -> + %% Example from RFC-2781. "*=Ra", where "*" represents a + %% hypothetical Ra hieroglyph (code point 16#12345). + + %% Give the compiler a change to do some constant propagation. + RaHieroglyph = 16#12345, + + %% First as a list of Unicode characters. + {[RaHieroglyph,16#3D,16#52,16#61], + + %% Big endian (the two binaries should be equal). + <<RaHieroglyph/big-utf16,16#3D/big-utf16,16#52/big-utf16,16#61/big-utf16>>, + <<16#D8,16#08,16#DF,16#45,16#00,16#3D,16#00,16#52,16#00,16#61>>, + + %% Little endian (the two binaries should be equal). + <<RaHieroglyph/little-utf16,16#3D/little-utf16, + 16#52/little-utf16,16#61/little-utf16>>, + <<16#08,16#D8,16#45,16#DF,16#3D,16#00,16#52,16#00,16#61,16#00>>}. + +utf32_data() -> + %% "A<NOT IDENTICAL TO><ALPHA>." + NotIdentical = 16#2262, + {[16#0041,NotIdentical,16#0391,16#002E], + + %% Big endian. + <<16#0041/utf32,NotIdentical/utf32,16#0391/utf32,16#002E/utf32>>, + <<16#41:32,NotIdentical:32,16#0391:32,16#2E:32>>, + + %% Little endian. + <<16#0041/little-utf32,NotIdentical/little-utf32, + 16#0391/little-utf32,16#002E/little-utf32>>, + <<16#41:32/little,NotIdentical:32/little, + 16#0391:32/little,16#2E:32/little>>}. diff --git a/lib/debugger/test/bug_SUITE.erl b/lib/debugger/test/bug_SUITE.erl new file mode 100644 index 0000000000..cf732c8115 --- /dev/null +++ b/lib/debugger/test/bug_SUITE.erl @@ -0,0 +1,79 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(bug_SUITE). + +-include("test_server.hrl"). + +-export([all/1]). + +-export([ticket_tests/1]). + +-export([otp2163/1, otp4845/1]). + +all(suite) -> [ticket_tests]. + +ticket_tests(doc) -> ["Tests tickets regarding bugs"]; +ticket_tests(suite) -> [otp2163, otp4845]. + +otp2163(doc) -> ["BIF exit reason"]; +otp2163(suite) -> []; +otp2163(Config) when list(Config) -> + ?line DataDir = ?config(data_dir, Config), + + %% First compile and get the expected results: + + ?line FileName = filename:join(DataDir, "otp2163"), + ?line {module,otp2163} = code:load_abs(FileName), + + ?line {'EXIT',{badarg,[ApplyRes|_]}} = (catch otp2163:apply_test()), + ?line {'EXIT',{badarg,[ListRes|_]}} = (catch otp2163:list_to_atom_test()), + + %% Then interpret, and check if the results are OK. + ?line {module,otp2163} = int:i(FileName), + + ?line ok = io:format("Expecting ~p", [ApplyRes]), + ?line {'EXIT',{badarg,[ApplyRes|_]}} = (catch otp2163:apply_test()), + ?line ok = io:format("Expecting ~p", [ListRes]), + ?line {'EXIT',{badarg,[ListRes|_]}} = (catch otp2163:list_to_atom_test()), + ok. + + +otp4845(doc) -> ["BIF not loading and not bug compatible, OTP-4845 OTP-4859"]; +otp4845(suite) -> []; +otp4845(Config) when list(Config) -> + ?line DataDir = ?config(data_dir, Config), + + %% First compile and get the expected results: + + ?line FileName = filename:join(DataDir, "otp4845"), + ?line {module,otp4845} = code:load_abs(FileName), + + ?line CompiledRes = (catch otp4845:test()), + ?line ok = io:format("Compiled ~p", [CompiledRes]), + + %% Then interpret, and check if the results are OK. + ?line {module,otp4845} = int:i(FileName), + + ?line IntRes = (catch otp4845:test()), + ?line ok = io:format("Interpreted ~p", [IntRes]), + + ?line CompiledRes = IntRes, + ok. diff --git a/lib/debugger/test/bug_SUITE_data/Makefile.src b/lib/debugger/test/bug_SUITE_data/Makefile.src new file mode 100644 index 0000000000..792b3299e1 --- /dev/null +++ b/lib/debugger/test/bug_SUITE_data/Makefile.src @@ -0,0 +1,25 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +all: otp2163.@EMULATOR@ otp4845.@EMULATOR@ +EFLAGS=+debug_info + +otp2163.@EMULATOR@: otp2163.erl + erlc $(EFLAGS) otp2163.erl +otp4845.@EMULATOR@: otp4845.erl + erlc $(EFLAGS) otp4845.erl diff --git a/lib/debugger/test/bug_SUITE_data/otp2163.erl b/lib/debugger/test/bug_SUITE_data/otp2163.erl new file mode 100644 index 0000000000..4e3c487ef7 --- /dev/null +++ b/lib/debugger/test/bug_SUITE_data/otp2163.erl @@ -0,0 +1,60 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%% Purpose : Test OTP-2163 + +-module(otp2163). + + +-export([apply_test/0, list_to_atom_test/0, error/1]). +-export([test/0]). + +apply_test() -> + M = {}, + apply(M,dummy,[]). + +list_to_atom_test() -> + list_to_atom(id({1,2})). + +id(I) -> I. + +%% OTP-4845 OTP 4859 +-record(sune, {a,sd,g,s}). +-record(error, {a,sd,g,s}). + +test() -> + sune = error(#sune{}), + {false,false} = error(false), + {true,true} = error(true), + error(#error{}). + +error(X) -> + if + is_record(X, sune) -> + sune; + X -> + {true, X}; + not X -> + {false, X}; + not is_record(X, error) -> + error; + true -> + ok + end. diff --git a/lib/debugger/test/bug_SUITE_data/otp4845.erl b/lib/debugger/test/bug_SUITE_data/otp4845.erl new file mode 100644 index 0000000000..18ca08b977 --- /dev/null +++ b/lib/debugger/test/bug_SUITE_data/otp4845.erl @@ -0,0 +1,52 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%% Purpose : Test OTP-4845 + +-module(otp4845). + + +%%-export([error/1]). +-export([test/0]). + +%% OTP-4845 OTP 4859 +-record(sune, {a,sd,g,s}). +-record(error, {a,sd,g,s}). + +test() -> + R1 = error(#sune{}), + R2 = error(false), + R3 = error(true), + R4 = error(#error{}), + {R1,R2,R3,R4}. + +error(X) -> + if + is_record(X, sune) -> + sune; + X -> + {true, X}; + not X -> + {false, X}; + not is_record(X, error) -> + error; + true -> + ok + end. diff --git a/lib/debugger/test/cleanup.erl b/lib/debugger/test/cleanup.erl new file mode 100644 index 0000000000..59b4c35ac7 --- /dev/null +++ b/lib/debugger/test/cleanup.erl @@ -0,0 +1,45 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(cleanup). + +-export([all/1, cleanup/1]). + +-include("test_server.hrl"). + +all(suite) -> {req, [interpreter], [cleanup]}. + +cleanup(suite) -> []; +cleanup(_) -> + ?line Mods = int:interpreted(), + ?line ok = int:n(Mods), + case whereis(interpret) of + undefined -> + ok; + Pid -> + exit(Pid, kill) + end, + case whereis(int_db) of + undefined -> + ok; + Pid2 -> + exit(Pid2, kill) + end, + ok. diff --git a/lib/debugger/test/dbg_ui_SUITE.erl b/lib/debugger/test/dbg_ui_SUITE.erl new file mode 100644 index 0000000000..629aac9fd6 --- /dev/null +++ b/lib/debugger/test/dbg_ui_SUITE.erl @@ -0,0 +1,288 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(dbg_ui_SUITE). + + +-include("test_server.hrl"). + + +% Test server specific exports +-export([all/1]). +-export([function_tests/1]). + + +% Test cases must be exported. +-export ([dbg_ui/1]). + + + + + +% Manual test suites/cases exports +-export([manual_tests/1]). +-export([start1/1, interpret1/1, quit1/1, + start2/1, interpret2/1, break2/1, options2/1, quit2/1, + interpret3/1, all_step3/1,all_next3/1,save3/1,restore3/1,finish3/1, + killinit3/1, killone3/1, killall3/1, deleteone3/1, deleteall3/1, + viewbreak4/1, delete4/1, + attach5/1, normal5/1, exit5/1, options5/1, + distsetup6/1, all_step6/1, all_next6/1]). + + + + +-export([init_per_testcase/2, fin_per_testcase/2]). + + + +init_per_testcase(_Func, Config) -> + Dog=test_server:timetrap(60*1000), + [{watchdog, Dog}|Config]. + +fin_per_testcase(_Func, Config) -> + Dog=?config(watchdog, Config), + test_server:timetrap_cancel(Dog). + + +all (suite)-> + {req, [debugger], [function_tests, manual_tests]}. + + +function_tests (doc) -> + ["Tests documented functions"]; + +function_tests (suite) -> + [dbg_ui]. + + + +dbg_ui (doc) -> + ["Debugger GUI"]; + +dbg_ui (suite) -> + []; + +dbg_ui (_Config) -> + case os:getenv("DISPLAY") of + false -> + {skipped,"No display"}; + Other when list(Other) -> +% ?line {ok, Pid} = debugger:start (), +% ?line ok = is_pid (Pid), +% ?line true = erlang:is_process_alive(Pid), +% ?line ok = debugger:stop(), +% ?line false = erlang:is_process_alive(Pid) + {skipped,"Gunilla: Workaround"} + end. + + + + + + +%% check/2 - returns the result for the specified testcase. +%% pass - means the user has run the case, and it passed +%% fail - means the user has run the case, and it failed +%% unknown - means the user has (tried to) run the case, and the result is unclear. +%% skip - means the user has not yet run the case. + +check(Case, Config) -> + + ?line DataDir = ?config(data_dir, Config), + ?line ResultFileName = filename:join([DataDir, "manual_results.erl"]), + case file:consult(ResultFileName) of + {ok, Results} -> + ?line io:format("Results: ~p~n",[Results]), + case Results of + [] -> + no_result; + %% Incomplete "sanity" check of file contents. + [{_Key,_Value}|_Rest] -> + case lists:keysearch(Case, 1, Results) of + {value, {Case, Value}} -> + Value; % pass, fail, unknown + false -> + no_result; % skip + _Otherwise -> + {error, "Contents of results file not valid"} + end; + _Otherwise2 -> + {error, "Contents of results file not valid"} + end; + _Otherwise3 -> + {error, "Problems reading results file"} + end. + + + + + + +-define(MAN_CASE(Name,Doc, Description), + Name(doc) -> [Doc]; + Name(suite) -> []; + Name(Config) -> + ?line io:format("Checking ~p~n",[Name]), + ?line io:format("Config = ~p~n",[Config]), + case check(Name, Config) of + pass -> + ?line ok; + fail -> + ?line test_server:fail("Manual test failed"); + unknown -> + ?line {skipped, "Manual test result unknown"}; + + no_result -> + ?line {skipped, Description}; + + {error, _Reason} -> +%% Text = lists:flatten( +%% io_lib:format("[File problem: ~s]~s", +%% [Reason,Description])), + ?line {skipped, Description} + end + ). + + + + +manual_tests(doc) -> ["Manual tests"]; +manual_tests(suite) -> [start1, interpret1, quit1, + start2, interpret2, break2, options2, + interpret3, all_step3,all_next3,save3,restore3,finish3, + killinit3, killone3, killall3, deleteone3, deleteall3, + viewbreak4, delete4, + attach5, normal5, exit5, options5, + distsetup6, all_step6, all_next6 + ]. + + + + + + +%% SET 1 +?MAN_CASE(start1, "Start the debugger from the toolbar", + "Before proceeding with the test cases, please move or remove +the directory .erlang_tools/debugger in your home directory. Next, +please start the debugger from the toolbar"). + +?MAN_CASE(interpret1, "Interpreting modules", + "In this test case and all of the ones following, the source code +files to use can be found in the test data directory for this debugger test + suite (probably in +/clearcase/otp/tools/debugger/test/dbg_ui_SUITE_data/manual_data/src ). +Interpret one module"). + +?MAN_CASE(quit1, "Quit the debugger", +"Quit the debugger using File->Exit in the main window"). + + +%% SET 2 +?MAN_CASE(start2, "Start the debugger from the shell", +"Start the debugger from the shell. Use debugger:start()"). + +?MAN_CASE(interpret2, "Interpret all modules", +"Interpret all modules"). + +?MAN_CASE(break2, "Set break points", +"Set break points"). + +?MAN_CASE(options2, "Set options to attach on break", +"Set options to attach on break"). + +?MAN_CASE(quit2, "Quit the debugger", +"Quit the debugger using the close box in the main window title frame"). + + +%% SET3 +?MAN_CASE(interpret3, "Test attach options", +"Start the debugger and interpret the modules [test, lists1, ordsets1]. Close the Interpret dialog. Set Attach on First Call and Attach on Break."). + +?MAN_CASE(all_step3, "Click Step through all evaluation", +"In the shell, call test:test1(). Use the Step button, the Process->Step menu item and the ctrl-s shortcut to step through the *entire* execution of the call. (Approx 36 steps). Then close the Attach window. The result printed in the shell should be: {\"peter\",[1,2,4,a,b,c],\"olin\"}"). + +?MAN_CASE(all_next3,"Click Next through all evaluation", +"Again call test:test1() in the shell. This time Use the Next button, the Process->Next menu and the ctrl-n shortcut to quickly step over the execution of the four lines in the test1-function. The result printed in the shell should be: {\"peter\",[1,2,4,a,b,c],\"olin\"}"). + +?MAN_CASE(save3, "Save the debugger state", +"Use File->Save Settings to save the debugger state with the name 'three.state'"). + +?MAN_CASE(restore3,"Quit the debugger, restart and restore the state", +"Quit the debugger. Start it again. Use File->Load Settings to restore the state saved in 'three.state'. Check that the Attach-options are the same as what you set them to in the interpret3 test case. Check that the three modules [test,lists1,ordsets1] are interpreted."). + + +?MAN_CASE(finish3, "Finish the current function body", +"Call the fucntion test:test1() from the shell. Press Finish to evaluate the remaining lines in the function. The result printed in the shell should be: {\"peter\",[1,2,4,a,b,c],\"olin\"}"). + +?MAN_CASE(killinit3,"Set up for killing and clearing processes", +"Call test:test2() from the shell. Set a break point at the last line of test:test2. Click Continue. This should open three new attach windows. One for each spawn called in test:test2/0. "). + +?MAN_CASE(killone3, "Kill a process and clear it", +"In one of the newly openend Attach windows: select Process->Kill. A message should appear above the Code Area in the Attach window. Use Windows->Monitor to verify that the Monitor window also shows that the process has been killed. In the Monitor window: select Edit->Clear. This should do two things: 1) close/remove the window of the killed process. 2) Remove the entry of the killed process from the monitor window."). + +?MAN_CASE(killall3,"KIll all processes, and clear them", +"In the Monitor window: Select Edit->Kill All. Verify that all processes have been killed (in their respective windows and in the monitor window). Windows will be raised as their processes die. Next select, Edit->Clear. All attach windows should now be closed. Their entris should also disappear from the monitor window. The shell should have reported: ** exited: killed **"). + +?MAN_CASE(deleteone3,"Delete/uniterpret one module", +"In the Monitor window: Select Module->test->Delete. This should remove the breakpoints set in the test module, and the test module should disappear from the Module menu."). + +?MAN_CASE(deleteall3,"Delete/uniterpret all modules", +"In the Monitor window: Select Module->Delete All Modules. This should remove all modules from the Module menu. "). + +%% SET 4 + + + +?MAN_CASE(viewbreak4, "Test the View window", +"Restore the settings from the three.state file again. In the Monitor window: Use Module->test->View to view the source code of the test module. In the View window, select Break->Line Break and set a break at line 53. Check that it appears in the View window and in the Monitor Window Break-menu. Also in the View window, select Break->Function Break and set a break at function test:test4. Check that the break (at line 59) appears in the View Window and in the Monitor Window Break-menu."). + +?MAN_CASE(delete4, "Remove breaks", +"Use the Break->Delete All function in the View window to remove all breaks in the test module. Check that they are all removed. Close the View window."). + +%% SET 5 + +?MAN_CASE(attach5,"Set attach options", +"Set the attach options to only attach on exit"). + +?MAN_CASE(normal5, "Test normal exit", +"Call test:test12(normal) in the shell. This should return the atom 'done', and no windows should be opened."). + +?MAN_CASE(exit5, "Test abnormal exit", +"Call test:test12(crash) in the shell. This should give the error message ** exited: crash **, and an attach window should be opened highlighting the last line in the test12-function."). + +?MAN_CASE(options5, "Experiment with the frames in the attach window", +"Try all possible configurations of the [Button, Evaluator, Bindings, Trace] Frames in the attach window and see that the expected frames are shown/hidden."). + + +%% SET 6 (Distribution) + +?MAN_CASE(distsetup6,"Set up distribution", +"Start two erlang systems [foo,bar] (with option -sname), make them aware of eachother using net_adm:ping/1. Start the debugger on foo. Interpret the modules [test, lists1, ordsets1]. Set attach on First call. "). + + + + +?MAN_CASE(all_step6, "Click Step through all evaluation", +"In the bar shell, call test:test1().This should open an attach window. Use the Step button, the Process->Step menu item and the ctrl-s shortcut to step through the *entire* execution of the call. (Approx 36 steps). Then close the Attach window. The result printed in the bar shell should be: {\"peter\",[1,2,4,a,b,c],\"olin\"}"). + +?MAN_CASE(all_next6,"Click Next through all evaluation", +"Again, in the bar shell, call test:test1(). This time Use the Next button, the Process->Next menu and the ctrl-n shortcut to quickly step over the execution of the four lines in the test1-function. The result printed in the shell should be: {\"peter\",[1,2,4,a,b,c],\"olin\"}"). diff --git a/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/lists1.erl b/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/lists1.erl new file mode 100644 index 0000000000..0214983c11 --- /dev/null +++ b/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/lists1.erl @@ -0,0 +1,469 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Purpose : Basic lists processing functions. + +-module(lists1). + + +-export([member/2, append/2, append/1, subtract/2, reverse/1, reverse/2, + nth/2, nthtail/2, prefix/2, suffix/2, last/1, + seq/2, seq/3, sum/1, duplicate/2, min/1, max/1, sublist/2, sublist/3, + delete/2, sort/1, merge/2, concat/1, + flatten/1, flatten/2, flat_length/1, flatlength/1, + keymember/3, keysearch/3, keydelete/3, keyreplace/4, + keysort/2, keymerge/3, keymap/3, keymap/4]). + +-export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2,zf/2, + mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,splitwith/2]). +-export([all/3,any/3,map/3,flatmap/3,foldl/4,foldr/4,filter/3,zf/3, + mapfoldl/4,mapfoldr/4,foreach/3]). + +%% member(X, L) -> (true | false) +%% test if X is a member of the list L + +member(X, [X|_]) -> true; +member(X, [_|Y]) -> + member(X, Y); +member(X, []) -> false. + +%% append(X, Y) appends lists X and Y + +append(L1, L2) -> L1 ++ L2. + +%% append(L) appends the list of lists L + +append([E]) -> E; +append([H|T]) -> H ++ append(T); +append([]) -> []. + +%% subtract(List1, List2) subtract elements in List2 form List1. + +subtract(L1, L2) -> L1 -- L2. + +%% reverse(L) reverse all elements in the list L + +reverse(X) -> reverse(X, []). + +reverse([H|T], Y) -> + reverse(T, [H|Y]); +reverse([], X) -> X. + +%% nth(N, L) returns the N`th element of the list L +%% nthtail(N, L) returns the N`th tail of the list L + +nth(1, [H|T]) -> H; +nth(N, [_|T]) when N > 1 -> + nth(N - 1, T). + +nthtail(1, [H|T]) -> T; +nthtail(N, [H|T]) when N > 1 -> + nthtail(N - 1, T); +nthtail(0, L) when list(L) -> L. + +%% prefix(Prefix, List) -> (true | false) + +prefix([X|PreTail], [X|Tail]) -> + prefix(PreTail, Tail); +prefix([], List) -> true; +prefix(_,_) -> false. + + +%% suffix(Suffix, List) -> (true | false) + +suffix(Suffix, Suffix) -> true; +suffix(Suffix, [_|Tail]) -> + suffix(Suffix, Tail); +suffix(Suffix, []) -> false. + +%% last(List) returns the last element in a list. + +last([E]) -> E; +last([E|Es]) -> + last(Es). + +%% seq(Min, Max) -> [Min,Min+1, ..., Max] +%% seq(Min, Max, Incr) -> [Min,Min+Incr, ..., Max] +%% returns the sequence Min..Max +%% Min <= Max and Min and Max must be integers + +seq(Min, Max) when integer(Min), integer(Max), Min =< Max -> + seq(Min, Max, 1, []). + +seq(Min, Max, Incr) -> + seq(Min, Min + ((Max-Min) div Incr) * Incr, Incr, []). + +seq(Min, Min, I, L) -> [Min|L]; +seq(Min, Max, I, L) -> seq(Min, Max-I, I, [Max|L]). + +%% sum(L) suns the sum of the elements in L + +sum(L) -> sum(L, 0). +sum([H|T], Sum) -> sum(T, Sum + H); +sum([], Sum) -> Sum. + +%% duplicate(N, X) -> [X,X,X,.....,X] (N times) +%% return N copies of X + +duplicate(N, X) when integer(N), N >= 0 -> duplicate(N, X, []). + +duplicate(0, _, L) -> L; +duplicate(N, X, L) -> duplicate(N-1, X, [X|L]). + + +%% min(L) -> returns the minimum element of the list L + +min([H|T]) -> min(T, H). + +min([H|T], Min) when H < Min -> min(T, H); +min([_|T], Min) -> min(T, Min); +min([], Min) -> Min. + +%% max(L) -> returns the maximum element of the list L + +max([H|T]) -> max(T, H). + +max([H|T], Max) when H > Max -> max(T, H); +max([_|T], Max) -> max(T, Max); +max([], Max) -> Max. + +%% sublist(List, Start, Length) +%% Returns the sub-list starting at Start of length Length. + +sublist(List, S, L) when L >= 0 -> + sublist(nthtail(S-1, List), L). + +sublist([H|T], L) when L > 0 -> + [H|sublist(T, L-1)]; +sublist(List, L) -> []. + +%% delete(Item, List) -> List' +%% Delete the first occurance of Item from the list L. + +delete(Item, [Item|Rest]) -> Rest; +delete(Item, [H|Rest]) -> + [H|delete(Item, Rest)]; +delete(Item, []) -> []. + +%% sort(L) -> sorts the list L + +sort([X]) -> [X]; +sort([]) -> []; +sort(X) -> split_and_sort(X, [], []). + +split_and_sort([A,B|T], X, Y) -> + split_and_sort(T, [A|X], [B|Y]); +split_and_sort([H], X, Y) -> + split_and_sort([], [H|X], Y); +split_and_sort([], X, Y) -> + merge(sort(X), sort(Y), []). + +%% merge(X, Y) -> L +%% merges two sorted lists X and Y + +merge(X, Y) -> merge(X, Y, []). + +merge([H1|T1], [H2|T2], L) when H1 < H2 -> + merge(T1, [H2|T2], [H1|L]); +merge(T1, [H2|T2], L) -> + merge(T1, T2, [H2|L]); +merge([H|T], T2, L) -> + merge(T, T2, [H|L]); +merge([], [], L) -> + reverse(L). + +%% concat(L) concatinate the list representation of the elements +%% in L - the elements in L can be atoms, integers of strings. +%% Returns a list of characters. + +concat(List) -> + flatmap(fun thing_to_list/1, List). + +thing_to_list(X) when integer(X) -> integer_to_list(X); +thing_to_list(X) when float(X) -> float_to_list(X); +thing_to_list(X) when atom(X) -> atom_to_list(X); +thing_to_list(X) when list(X) -> X. %Assumed to be a string + +%% flatten(List) +%% flatten(List, Tail) +%% Flatten a list, adding optional tail. + +flatten(List) -> + flatten(List, [], []). + +flatten(List, Tail) -> + flatten(List, [], Tail). + +flatten([H|T], Cont, Tail) when list(H) -> + flatten(H, [T|Cont], Tail); +flatten([H|T], Cont, Tail) -> + [H|flatten(T, Cont, Tail)]; +flatten([], [H|Cont], Tail) -> + flatten(H, Cont, Tail); +flatten([], [], Tail) -> + Tail. + +%% flat_length(List) (undocumented can be rmove later) +%% Calculate the length of a list of lists. + +flat_length(List) -> flatlength(List). + +%% flatlength(List) +%% Calculate the length of a list of lists. + +flatlength(List) -> + flatlength(List, 0). + +flatlength([H|T], L) when list(H) -> + flatlength(H, flatlength(T, L)); +flatlength([H|T], L) -> + flatlength(T, L + 1); +flatlength([], L) -> L. + +%% keymember(Key, Index, [Tuple]) +%% keysearch(Key, Index, [Tuple]) +%% keydelete(Key, Index, [Tuple]) +%% keyreplace(Key, Index, [Tuple], NewTuple) +%% keysort(Index, [Tuple]) +%% keymerge(Index, [Tuple], [Tuple]) +%% keymap(Function, Index, [Tuple]) +%% keymap(Function, ExtraArgs, Index, [Tuple]) + +keymember(Key, N, [T|Ts]) when element(N, T) == Key -> true; +keymember(Key, N, [T|Ts]) -> + keymember(Key, N, Ts); +keymember(Key, N, []) -> false. + +keysearch(Key, N, [H|T]) when element(N, H) == Key -> + {value, H}; +keysearch(Key, N, [H|T]) -> + keysearch(Key, N, T); +keysearch(Key, N, []) -> false. + +keydelete(Key, N, [H|T]) when element(N, H) == Key -> T; +keydelete(Key, N, [H|T]) -> + [H|keydelete(Key, N, T)]; +keydelete(Key, N, []) -> []. + +keyreplace(Key, Pos, [Tup|Tail], New) when element(Pos, Tup) == Key -> + [New|Tail]; +keyreplace(Key, Pos, [H|T], New) -> + [H|keyreplace(Key, Pos, T, New)]; +keyreplace(Key, Pos, [], New) -> []. + +keysort(Index, [X]) -> [X]; +keysort(Index, []) -> []; +keysort(Index, X) -> split_and_keysort(X, [], [], Index). + +split_and_keysort([A,B|T], X, Y, Index) -> + split_and_keysort(T, [A|X], [B|Y], Index); +split_and_keysort([H], X, Y, Index) -> + split_and_keysort([], [H|X], Y, Index); +split_and_keysort([], X, Y, Index) -> + keymerge(Index, keysort(Index, X), keysort(Index, Y), []). + +keymerge(Index, X, Y) -> keymerge(Index, X, Y, []). + +keymerge(I, [H1|T1], [H2|T2], L) when element(I, H1) < element(I, H2) -> + keymerge(I, T1, [H2|T2], [H1|L]); +keymerge(Index, T1, [H2|T2], L) -> + keymerge(Index,T1, T2, [H2|L]); +keymerge(Index,[H|T], T2, L) -> + keymerge(Index,T, T2, [H|L]); +keymerge(Index, [], [], L) -> + reverse(L). + +keymap(Fun, Index, [Tup|Tail]) -> + [setelement(Index, Tup, Fun(element(Index, Tup)))|keymap(Fun, Index, Tail)]; +keymap( _, _ , []) -> []. + +keymap(Fun, ExtraArgs, Index, [Tup|Tail]) -> + [setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))| + keymap(Fun, ExtraArgs, Index, Tail)]; +keymap( _, _ , _, []) -> []. + +%% all(Predicate, List) +%% any(Predicate, List) +%% map(Function, List) +%% flatmap(Function, List) +%% foldl(Function, First, List) +%% foldr(Function, Last, List) +%% filter(Predicate, List) +%% zf(Function, List) +%% mapfoldl(Function, First, List) +%% mapfoldr(Function, Last, List) +%% foreach(Function, List) +%% takewhile(Predicate, List) +%% dropwhile(Predicate, List) +%% splitwith(Predicate, List) +%% for list programming. Function here is either a 'fun' or a tuple +%% {Module,Name} and we use apply/2 to evaluate. The name zf is a joke! +%% +%% N.B. Unless where the functions actually needs it only foreach/2/3, +%% which is meant to be used for its side effects, has a defined order +%% of evaluation. +%% +%% There are also versions with an extra argument, ExtraArgs, which is a +%% list of extra arguments to each call. + +all(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> all(Pred, Tail); + false -> false + end; +all(Pred, []) -> true. + +any(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> true; + false -> any(Pred, Tail) + end; +any(Pred, []) -> false. + +map(F, List) -> [ F(E) || E <- List ]. + +flatmap(F, [Hd|Tail]) -> + F(Hd) ++ flatmap(F, Tail); +flatmap(F, []) -> []. + +foldl(F, Accu, [Hd|Tail]) -> + foldl(F, F(Hd, Accu), Tail); +foldl(F, Accu, []) -> Accu. + +foldr(F, Accu, [Hd|Tail]) -> + F(Hd, foldr(F, Accu, Tail)); +foldr(F, Accu, []) -> Accu. + +filter(Pred, List) -> [ E || E <- List, Pred(E) ]. + +zf(F, [Hd|Tail]) -> + case F(Hd) of + true -> + [Hd|zf(F, Tail)]; + {true,Val} -> + [Val|zf(F, Tail)]; + false -> + zf(F, Tail) + end; +zf(F, []) -> []. + +foreach(F, [Hd|Tail]) -> + F(Hd), + foreach(F, Tail); +foreach(F, []) -> ok. + +mapfoldl(F, Accu0, [Hd|Tail]) -> + {R,Accu1} = F(Hd, Accu0), + {Rs,Accu2} = mapfoldl(F, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl(F, Accu, []) -> {[],Accu}. + +mapfoldr(F, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr(F, Accu0, Tail), + {R,Accu2} = F(Hd, Accu1), + {[R|Rs],Accu2}; +mapfoldr(F, Accu, []) -> {[],Accu}. + +takewhile(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> [Hd|takewhile(Pred, Tail)]; + false -> [] + end; +takewhile(Pred, []) -> []. + +dropwhile(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> dropwhile(Pred, Tail); + false -> [Hd|Tail] + end; +dropwhile(Pred, []) -> []. + +splitwith(Pred, List) -> splitwith(Pred, List, []). + +splitwith(Pred, [Hd|Tail], Taken) -> + case Pred(Hd) of + true -> splitwith(Pred, Tail, [Hd|Taken]); + false -> {reverse(Taken), [Hd|Tail]} + end; +splitwith(Pred, [], Taken) -> {reverse(Taken),[]}. + +%% Versions of the above functions with extra arguments. + +all(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> all(Pred, Eas, Tail); + false -> false + end; +all(Pred, Eas, []) -> true. + +any(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> true; + false -> any(Pred, Eas, Tail) + end; +any(Pred, Eas, []) -> false. + +map(F, Eas, List) -> [ apply(F, [E|Eas]) || E <- List ]. + +flatmap(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]) ++ flatmap(F, Eas, Tail); +flatmap(F, Eas, []) -> []. + +foldl(F, Eas, Accu, [Hd|Tail]) -> + foldl(F, Eas, apply(F, [Hd,Accu|Eas]), Tail); +foldl(F, Eas, Accu, []) -> Accu. + +foldr(F, Eas, Accu, [Hd|Tail]) -> + apply(F, [Hd,foldr(F, Eas, Accu, Tail)|Eas]); +foldr(F, Eas, Accu, []) -> + Accu. + +filter(Pred, Eas, List) -> [ E || E <- List, apply(Pred, [E|Eas]) ]. + +zf(F, Eas, [Hd|Tail]) -> + case apply(F, [Hd|Eas]) of + true -> + [Hd|zf(F, Eas, Tail)]; + {true,Val} -> + [Val|zf(F, Eas, Tail)]; + false -> + zf(F, Eas, Tail) + end; +zf(F, Eas, []) -> []. + +foreach(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]), + foreach(F, Eas, Tail); +foreach(F, Eas, []) -> ok. + +mapfoldl(F, Eas, Accu0, [Hd|Tail]) -> + {R,Accu1} = apply(F, [Hd,Accu0|Eas]), + {Rs,Accu2} = mapfoldl(F, Eas, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl(F, Eas, Accu, []) -> {[],Accu}. + +mapfoldr(F, Eas, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr(F, Eas, Accu0, Tail), + {R,Accu2} = apply(F, [Hd,Accu1|Eas]), + {[R|Rs],Accu2}; +mapfoldr(F, Eas, Accu, []) -> {[],Accu}. + +%% takewhile/2, dropwhile/2 and splitwith/2 do not have versions with +%% extra arguments as this going to be discontinued. diff --git a/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/ordsets1.erl b/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/ordsets1.erl new file mode 100644 index 0000000000..ea72150bca --- /dev/null +++ b/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/ordsets1.erl @@ -0,0 +1,188 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Purpose : Functions for manipulating sets as ordered lists. + +%% As yet some of these are not very efficiently written. + +-module(ordsets1). + +-export([new_set/0,is_set/1,set_to_list/1,list_to_set/1]). +-export([is_element/2,add_element/2,del_element/2]). +-export([union/2,union/1,intersection/2,intersection/1]). +-export([subtract/2,subset/2]). + +%% new_set() +%% Return a new empty ordered set. + +new_set() -> + []. + +%% is_set(Set) +%% Return 'true' if Set is an ordered set of elements, else 'false'. + +is_set([E|Es]) -> + is_set(Es, E); +is_set([]) -> + true. + +is_set([E2|Es], E1) when E1 < E2 -> + is_set(Es, E2); +is_set([E2|Es], E1) -> + false; +is_set([], E1) -> + true. + +%% set_to_list(OrdSet) +%% Return the elements in OrdSet as a list. + +set_to_list(S) -> + S. + +%% list_to_set(List) +%% Build an ordered set from the elements in List. + +list_to_set([E|Es]) -> + add_element(E, list_to_set(Es)); +list_to_set([]) -> + []. + +%% is_element(Element, OrdSet) +%% Return 'true' if Element is an element of OrdSet, else 'false'. + +is_element(E, [H|Es]) when E < H -> + false; +is_element(E, [H|Es]) when E == H -> + true; +is_element(E, [H|Es]) when E > H -> + is_element(E, Es); +is_element(E, []) -> + false. + +%% add_element(Element, OrdSet) +%% Return OrdSet with Element inserted in it. + +add_element(E, [H|Es]) when E < H -> + [E,H|Es]; +add_element(E, [H|Es]) when E == H -> + [H|Es]; +add_element(E, [H|Es]) when E > H -> + [H|add_element(E, Es)]; +add_element(E, []) -> + [E]. + +%% del_element(Element, OrdSet) +%% Return OrdSet but with Element removed. + +del_element(E, [H|Es]) when E < H -> + [H|Es]; +del_element(E, [H|Es]) when E == H -> + Es; +del_element(E, [H|Es]) when E > H -> + [H|del_element(E, Es)]; +del_element(E, []) -> + []. + +%% union(Set1, Set2) +%% Return the union of Set1 and Set2. + +union([H1|Es1], [H2|Es2]) when H1 < H2 -> + [H1|union(Es1, [H2|Es2])]; +union([H1|Es1], [H2|Es2]) when H1 == H2 -> + [H1|union(Es1, Es2)]; +union([H1|Es1], [H2|Es2]) when H1 > H2 -> + [H2|union([H1|Es1], Es2)]; +union([], Es2) -> + Es2; +union(Es1, []) -> + Es1. + +%% union(OrdSets) +%% Return the union of the list of sets. + +union([S1,S2|Ss]) -> + union1(union(S1,S2), Ss); +union([S]) -> + S; +union([]) -> + []. + +union1(S1, [S2|Ss]) -> + union1(union(S1, S2), Ss); +union1(S1, []) -> + S1. + +%% intersection(Set1, Set2) +%% Return the intersection of Set1 and Set2. + +intersection([H1|Es1], [H2|Es2]) when H1 < H2 -> + intersection(Es1, [H2|Es2]); +intersection([H1|Es1], [H2|Es2]) when H1 == H2 -> + [H1|intersection(Es1, Es2)]; +intersection([H1|Es1], [H2|Es2]) when H1 > H2 -> + intersection([H1|Es1], Es2); +intersection([], Es2) -> + []; +intersection(Es1, []) -> + []. + +%% intersection(OrdSets) +%% Return the intersection of the list of sets. + +intersection([S1,S2|Ss]) -> + intersection1(intersection(S1,S2), Ss); +intersection([S]) -> + S; +intersection([]) -> + []. + +intersection1(S1, [S2|Ss]) -> + intersection1(intersection(S1, S2), Ss); +intersection1(S1, []) -> + S1. + +%% subtract(Set1, Set2) +%% Return all and only the elements of Set1 which are not also in Set2. + +subtract([H1|Es1], [H2|Es2]) when H1 < H2 -> + [H1|subtract(Es1, [H2|Es2])]; +subtract([H1|Es1], [H2|Es2]) when H1 == H2 -> + subtract(Es1, Es2); +subtract([H1|Es1], [H2|Es2]) when H1 > H2 -> + subtract([H1|Es1], Es2); +subtract([], Es2) -> + []; +subtract(Es1, []) -> + Es1. + +%% subset(Set1, Set2) +%% Return 'true' when every element of Set1 is also a member of Set2, +%% else 'false'. + +subset([H1|Es1], [H2|Es2]) when H1 < H2 -> %H1 not in Set2 + false; +subset([H1|Es1], [H2|Es2]) when H1 == H2 -> + subset(Es1, Es2); +subset([H1|Es1], [H2|Es2]) when H1 > H2 -> + subset([H1|Es1], Es2); +subset([], Es2) -> + true; +subset(Es1, []) -> + false. diff --git a/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/test.erl b/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/test.erl new file mode 100644 index 0000000000..a48a7e112f --- /dev/null +++ b/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/test.erl @@ -0,0 +1,157 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(test). + +%%-compile(export_all). +-export([test1/0, + test2/0, + test3/0, + test4/0, + test5/0, + test6/1, + test7/0, + test8/1, + test9/0, + test10/0, + test11/0, + test12/1 + ]). + + +-export([test9_server/1]). + + +test1() -> + R1 = lists1:reverse("retep"), + R2 = ordsets1:list_to_set([b,c,a,2,4,1]), + R3 = lists1:reverse("nilo"), + {R1,R2, R3}. + +test2() -> + R1 = spawn(lists1,reverse,["retep"]), + R2 = spawn(ordsets1,list_to_set,[[b,c,a,2,4,1]]), + R3 = spawn(lists1,reverse,["nilo"]), + {R1,R2, R3}. + + +test3() -> + A = a, + Pid = spawn(?MODULE, test1,[]), + B = b, + {A, B, Pid}. + +test4() -> + Pid = spawn(?MODULE, test1,[]), + A = a, + B = b, + {A, B, Pid}. +test5() -> + L1 = [a,b,c], + L = length(L1), + A = a, + B = b, + {A, B, L, L1}. + + + +test6(0) -> + ok; +test6(N) when N>0 -> + spawn(lists1,reverse,["adolfiparisrorsirapifloda"]), + test6(N-1). + + +test7() -> + CurDirReturn = file:get_cwd(), + {ok, CurDir} = CurDirReturn, + DirListReturn = file:list_dir(CurDir), + {ok, DirList} = DirListReturn, + io:format("~w~n",[DirList]). + + +test8(List) -> + %% foo + %%bar + %% foo + %%bar + %% foo + %%bar + %% foo + %%bar + + L2 = [gamma|List], + {L2, List}. + +test9() -> + S1 = spawn(?MODULE, test9_server,[self()]), + S2 = spawn(?MODULE, test9_server,[bongo]), + S3 = spawn(?MODULE, test9_server,[42]), + + test9_loop(S1,S2,S3). + +test9_loop(S1,S2,S3) -> + receive + {S1, hej} -> + io:format("S1 ~n"), + test9_loop(S1,S2,S3); + {S2, hej} -> + io:format("S2 ~n"), + test9_loop(S1,S2,S3); + {S3, hej} -> + io:format("S3 ~n"), + test9_loop(S1,S2,S3) + end. + + +test9_server(Pid) -> + io:format("started server: ~p~n",[Pid]), + test9_server1(Pid). + +test9_server1(Pid) -> + Pad = {pad, Pid}, + test9_server2(Pad). + +test9_server2(Pad) -> + {pad, Pid} = Pad, + Pid ! {self(), hej}. + + + + + +test10() -> + receive + X -> + done + after 20000 -> + timeout + end. + +test11() -> + receive + X -> + done + end. + +test12(normal) -> + done; +test12(crash) -> + exit(crash). diff --git a/lib/debugger/test/debugger.spec b/lib/debugger/test/debugger.spec new file mode 100644 index 0000000000..cc8a5aff37 --- /dev/null +++ b/lib/debugger/test/debugger.spec @@ -0,0 +1 @@ +{topcase, {dir, "../debugger_test"}}. diff --git a/lib/debugger/test/debugger_SUITE.erl b/lib/debugger/test/debugger_SUITE.erl new file mode 100644 index 0000000000..4bd9057f98 --- /dev/null +++ b/lib/debugger/test/debugger_SUITE.erl @@ -0,0 +1,123 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(debugger_SUITE). + +%% Test break points. + +-include("test_server.hrl"). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2, + app_test/1,erts_debug/1,encrypted_debug_info/1, + no_abstract_code/1]). + +all(suite) -> + [app_test,erts_debug,no_abstract_code,encrypted_debug_info]. + +init_per_testcase(_Case, Config) -> + Dog=test_server:timetrap(?t:minutes(0.5)), + [{watchdog, Dog}|Config]. +fin_per_testcase(_Case, Config) -> + Dog=?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. + +app_test(Config) when is_list(Config) -> + ?line ?t:app_test(debugger), + ok. + +erts_debug(Config) when is_list(Config) -> + c:l(erts_debug), + ok. + +no_abstract_code(Config) when is_list(Config) -> + ?line PrivDir = ?config(priv_dir, Config), + ?line Simple = filename:join(PrivDir, "simple"), + ?line Source = Simple ++ ".erl", + ?line BeamFile = Simple ++ ".beam", + ?line simple_file(Source), + + %% Compile module without abstract code. + CompileFlags = [{outdir,PrivDir}], + ?line {ok,_} = compile:file(Source, CompileFlags), + ?line error = int:i(Simple), + + %% Cleanup. + ?line ok = file:delete(Source), + ?line ok = file:delete(BeamFile), + + ok. + +encrypted_debug_info(Config) when is_list(Config) -> + try begin crypto:start(), crypto:info(), crypto:stop(), ok end of + ok -> + encrypted_debug_info_1(Config) + catch + error:_ -> + {skip,"The crypto application is missing or broken"} + end. + +encrypted_debug_info_1(Config) -> + ?line PrivDir = ?config(priv_dir, Config), + ?line Simple = filename:join(PrivDir, "simple"), + ?line Source = Simple ++ ".erl", + ?line BeamFile = Simple ++ ".beam", + ?line simple_file(Source), + + %% Compile module. + Key = "_This a Crypto Key_", + CompileFlags = [{outdir,PrivDir},debug_info,{debug_info_key,Key}], + ?line {ok,_} = compile:file(Source, CompileFlags), + + %% Interpret module + ?line ok = beam_lib:crypto_key_fun(simple_crypto_fun(Key)), + ?line {module,simple} = int:i(Simple), + + %% Remove key. + ?line {ok,_} = beam_lib:clear_crypto_key_fun(), + ?line error = int:i(Simple), + + %% Cleanup. + ?line ok = file:delete(Source), + ?line ok = file:delete(BeamFile), + + ok. + +simple_crypto_fun(Key) -> + fun(init) -> ok; + ({debug_info, des3_cbc, simple, _}) -> Key + end. + + +simple_file(File) -> + simple_file(File, simple). + +simple_file(File, Module) -> + simple_file(File, Module, member). + +simple_file(File, Module, F) -> + B = list_to_binary(["-module(", atom_to_list(Module), "). " + "-export([t/0]). " + "t() -> " + " t([]). " + "t(L) -> " + " lists:", + atom_to_list(F), "(a, L). "]), + ok = file:write_file(File, B). diff --git a/lib/debugger/test/debugger_test.erl b/lib/debugger/test/debugger_test.erl new file mode 100644 index 0000000000..a64bed5db1 --- /dev/null +++ b/lib/debugger/test/debugger_test.erl @@ -0,0 +1,154 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%%---------------------------------------------------------------------- +%%% Purpose : This is the test module to be used in with the test cases +%%% in the debugger test document. +%%%---------------------------------------------------------------------- + +-module(debugger_test). + + +-export ([installation_ok/0, + list/0, + fac/1, + c_break/1]). + + +-define (INT_DIR, "misc"). % The directory of the Interpreter directory +-define (INT, "interpreter"). % The Interpreter directory name. +-define (DBG, "debugger"). % Debugger name + + +%%% installation_ok /0 +%%% + +installation_ok () -> + debugger_ok (), + interpreter_ok (). + + + +%%% debugger_ok /0 +%%% + +debugger_ok () -> + L = code:get_path (), + + case debugger_in_codepath (L) of + {true, Msg} -> + out_put (Msg); + + Other -> + out_put (Other) + end. + + + +%%% debugger_in_codepath /2 +%%% + +debugger_in_codepath ([]) -> + Msg = io_lib:format ("False: ~s not in code path", [?DBG]), + lists:flatten (Msg); + +debugger_in_codepath ([Path | T]) -> + case string:str (Path, ?DBG) =/= 0 of + true -> + Msg = io_lib:format ("Ok: ~s in code path (~s)", [?DBG, Path]), + Msg1 = lists:flatten (Msg), + {true, Msg1}; + + _Other -> + debugger_in_codepath (T) + end. + + + +%%% interpreter_ok /0 +%%% + +interpreter_ok () -> + Root_dir = code:root_dir (), + Misc_dir = filename:join (Root_dir, ?INT_DIR), + + In_misc = case file:list_dir (Misc_dir) of + {ok, L} -> + lists:member (?INT, L); + + Other -> + Other + end, + + case In_misc of + true -> + Msg = io_lib:format ("Ok: ~s is in ~s", [?INT, ?INT_DIR]), + Msg1 = lists:flatten (Msg), + out_put (Msg1); + + Other1 -> + Msg = io_lib:format ("Error: interpreter in misc - ~s", [Other1]), + Msg1 = lists:flatten (Msg), + out_put (Msg1) + end. + + + +%%% list /0 +%%% + +list () -> + A = [1, 2, 3, 4, 5], + B = [a, b, c, d, e], + lists:append (A, B). + + + +%%% fac /1 +%%% + +fac (0) -> + 1; + + +fac (N) -> + N * fac (N - 1). + + + +%%% c_break /1 +%%% + +c_break (Bindings) -> + case int:get_binding ('N', Bindings) of + {value, 3} -> + true; + + _Other -> + false + end. + + + +%%% out_put /1 +%%% + +out_put (X) -> + io:format ("~n~p~n", [X]). diff --git a/lib/debugger/test/debugger_testdoc.fm5 b/lib/debugger/test/debugger_testdoc.fm5 Binary files differnew file mode 100644 index 0000000000..56882b8bd5 --- /dev/null +++ b/lib/debugger/test/debugger_testdoc.fm5 diff --git a/lib/debugger/test/erl_eval_SUITE.erl b/lib/debugger/test/erl_eval_SUITE.erl new file mode 100644 index 0000000000..fd4d28b2c7 --- /dev/null +++ b/lib/debugger/test/erl_eval_SUITE.erl @@ -0,0 +1,1388 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +-module(erl_eval_SUITE). +-export([all/1]). + +-export([guard_1/1, guard_2/1, + match_pattern/1, + match_bin/1, + string_plusplus/1, + pattern_expr/1, + guard_3/1, guard_4/1, + lc/1, + simple_cases/1, + unary_plus/1, + apply_atom/1, + otp_5269/1, + otp_6539/1, + otp_6543/1, + otp_6787/1, + otp_6977/1, + otp_7550/1, + otp_8133/1, + funs/1, + try_catch/1, + eval_expr_5/1]). + +%% +%% Define to run outside of test server +%% +%%-define(STANDALONE,1). + +-import(lists,[concat/1, sort/1]). + +-export([count_down/2, count_down_fun/0, do_apply/2, + local_func/3, local_func_value/2]). + +-ifdef(STANDALONE). +-define(config(A,B),config(A,B)). +-export([config/2]). +-define(line, noop, ). +config(priv_dir,_) -> + ".". +-else. +-include("test_server.hrl"). +-export([init_per_testcase/2, fin_per_testcase/2]). +% Default timetrap timeout (set in init_per_testcase). +-define(default_timeout, ?t:minutes(1)). +init_per_testcase(_Case, Config) -> + ?line Dog = ?t:timetrap(?default_timeout), + [{watchdog, Dog} | Config]. +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. +-endif. + +all(doc) -> + ["Test cases for the 'erl_eval' module."]; +all(suite) -> + [guard_1, guard_2, match_pattern, string_plusplus, pattern_expr, + match_bin, guard_3, guard_4, + lc, simple_cases, unary_plus, apply_atom, otp_5269, otp_6539, otp_6543, + otp_6787, otp_6977, otp_7550, otp_8133, funs, try_catch, eval_expr_5]. + +guard_1(doc) -> + ["(OTP-2405)"]; +guard_1(suite) -> + []; +guard_1(Config) when is_list(Config) -> + ?line {ok,Tokens ,_} = + erl_scan:string("if a+4 == 4 -> yes; true -> no end. "), + ?line {ok, [Expr]} = erl_parse:parse_exprs(Tokens), + ?line no = guard_1_compiled(), + ?line {value, no, []} = erl_eval:expr(Expr, []), + ok. + +guard_1_compiled() -> + if a+4 == 4 -> yes; true -> no end. + +guard_2(doc) -> + ["Similar to guard_1, but type-correct"]; +guard_2(suite) -> + []; +guard_2(Config) when is_list(Config) -> + ?line {ok,Tokens ,_} = + erl_scan:string("if 6+4 == 4 -> yes; true -> no end. "), + ?line {ok, [Expr]} = erl_parse:parse_exprs(Tokens), + ?line no = guard_2_compiled(), + ?line {value, no, []} = erl_eval:expr(Expr, []), + ok. + +guard_2_compiled() -> + if 6+4 == 4 -> yes; true -> no end. + +string_plusplus(doc) -> + ["OTP-3069: syntactic sugar string ++ ..."]; +string_plusplus(suite) -> + []; +string_plusplus(Config) when is_list(Config) -> + ?line check(fun() -> case "abc" of "ab" ++ L -> L end end, + "case \"abc\" of \"ab\" ++ L -> L end. ", + "c"), + ?line check(fun() -> case "abcde" of "ab" ++ "cd" ++ L -> L end end, + "case \"abcde\" of \"ab\" ++ \"cd\" ++ L -> L end. ", + "e"), + ?line check(fun() -> case "abc" of [97, 98] ++ L -> L end end, + "case \"abc\" of [97, 98] ++ L -> L end. ", + "c"), + ok. + +match_pattern(doc) -> + ["OTP-2983: match operator in pattern"]; +match_pattern(suite) -> + []; +match_pattern(Config) when is_list(Config) -> + ?line check(fun() -> case {a, b} of {a, _X}=Y -> {x,Y} end end, + "case {a, b} of {a, X}=Y -> {x,Y} end. ", + {x, {a, b}}), + ?line check(fun() -> case {a, b} of Y={a, _X} -> {x,Y} end end, + "case {a, b} of Y={a, X} -> {x,Y} end. ", + {x, {a, b}}), + ?line check(fun() -> case {a, b} of Y={a, _X}=Z -> {Z,Y} end end, + "case {a, b} of Y={a, X}=Z -> {Z,Y} end. ", + {{a, b}, {a, b}}), + ?line check(fun() -> A = 4, B = 28, <<13:(A+(X=B))>>, X end, + "begin A = 4, B = 28, <<13:(A+(X=B))>>, X end.", + 28), + ok. + +match_bin(doc) -> + ["binary match problems"]; +match_bin(suite) -> + []; +match_bin(Config) when is_list(Config) -> + ?line check(fun() -> <<"abc">> = <<"abc">> end, + "<<\"abc\">> = <<\"abc\">>. ", + <<"abc">>), + ?line check(fun() -> + <<Size,B:Size/binary,Rest/binary>> = <<2,"AB","CD">>, + {Size,B,Rest} + end, + "begin <<Size,B:Size/binary,Rest/binary>> = <<2,\"AB\",\"CD\">>, " + "{Size,B,Rest} end. ", + {2,<<"AB">>,<<"CD">>}), + ok. + +pattern_expr(doc) -> + ["OTP-3144: compile-time expressions in pattern"]; +pattern_expr(suite) -> + []; +pattern_expr(Config) when is_list(Config) -> + ?line check(fun() -> case 4 of 2+2 -> ok end end, + "case 4 of 2+2 -> ok end. ", + ok), + ?line check(fun() -> case 2 of +2 -> ok end end, + "case 2 of +2 -> ok end. ", + ok), + ok. + +guard_3(doc) -> + ["OTP-4518."]; +guard_3(suite) -> + []; +guard_3(Config) when is_list(Config) -> + ?line check(fun() -> if false -> false; true -> true end end, + "if false -> false; true -> true end.", + true), + ?line check(fun() -> if <<"hej">> == <<"hopp">> -> true; + true -> false end end, + "begin if <<\"hej\">> == <<\"hopp\">> -> true; + true -> false end end.", + false), + ?line check(fun() -> if <<"hej">> == <<"hej">> -> true; + true -> false end end, + "begin if <<\"hej\">> == <<\"hej\">> -> true; + true -> false end end.", + true), + ok. + +guard_4(doc) -> + ["OTP-4885."]; +guard_4(suite) -> + []; +guard_4(Config) when is_list(Config) -> + ?line check(fun() -> if {erlang,'+'}(3,a) -> true ; true -> false end end, + "if {erlang,'+'}(3,a) -> true ; true -> false end.", + false), + ?line check(fun() -> if {erlang,is_integer}(3) -> true ; true -> false end + end, + "if {erlang,is_integer}(3) -> true ; true -> false end.", + true), + ?line check(fun() -> [X || X <- [1,2,3], erlang:is_integer(X)] end, + "[X || X <- [1,2,3], erlang:is_integer(X)].", + [1,2,3]), + ?line check(fun() -> if is_atom(is_integer(a)) -> true ; true -> false end + end, + "if is_atom(is_integer(a)) -> true ; true -> false end.", + true), + ?line check(fun() -> if {erlang,is_atom}({erlang,is_integer}(a)) -> true; + true -> false end end, + "if {erlang,is_atom}({erlang,is_integer}(a)) -> true; " + "true -> false end.", + true), + ?line check(fun() -> if is_atom(3+a) -> true ; true -> false end end, + "if is_atom(3+a) -> true ; true -> false end.", + false), + ?line check(fun() -> if erlang:is_atom(3+a) -> true ; true -> false end + end, + "if erlang:is_atom(3+a) -> true ; true -> false end.", + false), + ok. + + +lc(doc) -> + ["OTP-4518."]; +lc(suite) -> + []; +lc(Config) when is_list(Config) -> + ?line check(fun() -> X = 32, [X || X <- [1,2,3]] end, + "begin X = 32, [X || X <- [1,2,3]] end.", + [1,2,3]), + ?line check(fun() -> X = 32, + [X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end, + %% "binsize variable" ^ + "begin X = 32, + [X || <<X:X>> <- [<<1:32>>,<<2:32>>,<<3:8>>]] end.", + [1,2]), + ?line check(fun() -> Y = 13,[X || {X,Y} <- [{1,2}]] end, + "begin Y = 13,[X || {X,Y} <- [{1,2}]] end.", + [1]), + ?line error_check("begin [A || X <- [{1,2}], 1 == A] end.", + {unbound_var,'A'}), + ?line error_check("begin X = 32, + [{Y,W} || X <- [1,2,32,Y=4], Z <- [1,2,W=3]] end.", + {unbound_var,'Y'}), + ?line error_check("begin X = 32,<<A:B>> = <<100:X>> end.", + {unbound_var,'B'}), + ?line check(fun() -> [X || X <- [1,2,3,4], not (X < 2)] end, + "begin [X || X <- [1,2,3,4], not (X < 2)] end.", + [2,3,4]), + ?line check(fun() -> [X || X <- [true,false], X] end, + "[X || X <- [true,false], X].", [true]), + ok. + +simple_cases(doc) -> + ["Simple cases, just to cover some code."]; +simple_cases(suite) -> + []; +simple_cases(Config) when is_list(Config) -> + ?line check(fun() -> A = $C end, "A = $C.", $C), + %% ?line check(fun() -> A = 3.14 end, "A = 3.14.", 3.14), + ?line check(fun() -> self() ! a, A = receive a -> true end end, + "begin self() ! a, A = receive a -> true end end.", + true), + ?line check(fun() -> c:flush(), self() ! a, self() ! b, self() ! c, + receive b -> b end, + {messages, [a,c]} = + erlang:process_info(self(), messages), + c:flush() end, + "begin c:flush(), self() ! a, self() ! b, self() ! c," + "receive b -> b end," + "{messages, [a,c]} =" + " erlang:process_info(self(), messages), c:flush() end.", + ok), + ?line check(fun() -> self() ! a, A = receive a -> true + after 0 -> false end end, + "begin self() ! a, A = receive a -> true" + " after 0 -> false end end.", + true), + ?line check(fun() -> c:flush(), self() ! a, self() ! b, self() ! c, + receive b -> b after 0 -> true end, + {messages, [a,c]} = + erlang:process_info(self(), messages), + c:flush() end, + "begin c:flush(), self() ! a, self() ! b, self() ! c," + "receive b -> b after 0 -> true end," + "{messages, [a,c]} =" + " erlang:process_info(self(), messages), c:flush() end.", + ok), + ?line check(fun() -> receive _ -> true after 10 -> false end end, + "receive _ -> true after 10 -> false end.", + false), + ?line check(fun() -> F = fun(A) -> A end, true = 3 == F(3) end, + "begin F = fun(A) -> A end, true = 3 == F(3) end.", + true), + ?line check(fun() -> F = fun(A) -> A end, true = 3 == apply(F, [3]) end, + "begin F = fun(A) -> A end, true = 3 == apply(F,[3]) end.", + true), + ?line check(fun() -> catch throw(a) end, "catch throw(a).", a), + ?line check(fun() -> catch a end, "catch a.", a), + ?line check(fun() -> 4 == 3 end, "4 == 3.", false), + ?line check(fun() -> not true end, "not true.", false), + ?line check(fun() -> -3 end, "-3.", -3), + + ?line error_check("3.0 = 4.0.", {badmatch,4.0}), + ?line check(fun() -> <<(3.0+2.0):32/float>> = <<5.0:32/float>> end, + "<<(3.0+2.0):32/float>> = <<5.0:32/float>>.", + <<5.0:32/float>>), + + ?line check(fun() -> false andalso kludd end, "false andalso kludd.", + false), + ?line check(fun() -> true andalso true end, "true andalso true.", + true), + ?line check(fun() -> true andalso false end, "true andalso false.", + false), + ?line check(fun() -> true andalso kludd end, "true andalso kludd.", + kludd), + ?line error_check("kladd andalso kludd.", {badarg,kladd}), + + ?line check(fun() -> if false andalso kludd -> a; true -> b end end, + "if false andalso kludd -> a; true -> b end.", + b), + ?line check(fun() -> if true andalso true -> a; true -> b end end, + "if true andalso true -> a; true -> b end.", + a), + ?line check(fun() -> if true andalso false -> a; true -> b end end, + "if true andalso false -> a; true -> b end.", + b), + + ?line check(fun() -> true orelse kludd end, + "true orelse kludd.", true), + ?line check(fun() -> false orelse false end, + "false orelse false.", false), + ?line check(fun() -> false orelse true end, + "false orelse true.", true), + ?line check(fun() -> false orelse kludd end, + "false orelse kludd.", kludd), + ?line error_check("kladd orelse kludd.", {badarg,kladd}), + ?line error_check("[X || X <- [1,2,3], begin 1 end].",{bad_filter,1}), + ?line error_check("[X || X <- a].",{bad_generator,a}), + + ?line check(fun() -> if true orelse kludd -> a; true -> b end end, + "if true orelse kludd -> a; true -> b end.", a), + ?line check(fun() -> if false orelse false -> a; true -> b end end, + "if false orelse false -> a; true -> b end.", b), + ?line check(fun() -> if false orelse true -> a; true -> b end end, + "if false orelse true -> a; true -> b end.", a), + + ?line check(fun() -> [X || X <- [1,2,3], X+2] end, + "[X || X <- [1,2,3], X+2].", []), + + ?line check(fun() -> [X || X <- [1,2,3], [X] == [X || X <- [2]]] end, + "[X || X <- [1,2,3], [X] == [X || X <- [2]]].", + [2]), + ?line check(fun() -> F = fun(1) -> ett; (2) -> zwei end, + ett = F(1), zwei = F(2) end, + "begin F = fun(1) -> ett; (2) -> zwei end, + ett = F(1), zwei = F(2) end.", + zwei), + ?line check(fun() -> F = fun(X) when X == 1 -> ett; + (X) when X == 2 -> zwei end, + ett = F(1), zwei = F(2) end, + "begin F = fun(X) when X == 1 -> ett; + (X) when X == 2 -> zwei end, + ett = F(1), zwei = F(2) end.", + zwei), + ?line error_check("begin F = fun(1) -> ett end, zwei = F(2) end.", + function_clause), + ?line check(fun() -> if length([1]) == 1 -> yes; + true -> no end end, + "if length([1]) == 1 -> yes; + true -> no end.", + yes), + ?line check(fun() -> if is_integer(3) -> true; true -> false end end, + "if is_integer(3) -> true; true -> false end.", true), + ?line check(fun() -> if integer(3) -> true; true -> false end end, + "if integer(3) -> true; true -> false end.", true), + ?line check(fun() -> if is_float(3) -> true; true -> false end end, + "if is_float(3) -> true; true -> false end.", false), + ?line check(fun() -> if float(3) -> true; true -> false end end, + "if float(3) -> true; true -> false end.", false), + ?line check(fun() -> if is_number(3) -> true; true -> false end end, + "if is_number(3) -> true; true -> false end.", true), + ?line check(fun() -> if number(3) -> true; true -> false end end, + "if number(3) -> true; true -> false end.", true), + ?line check(fun() -> if is_atom(a) -> true; true -> false end end, + "if is_atom(a) -> true; true -> false end.", true), + ?line check(fun() -> if atom(a) -> true; true -> false end end, + "if atom(a) -> true; true -> false end.", true), + ?line check(fun() -> if is_list([]) -> true; true -> false end end, + "if is_list([]) -> true; true -> false end.", true), + ?line check(fun() -> if list([]) -> true; true -> false end end, + "if list([]) -> true; true -> false end.", true), + ?line check(fun() -> if is_tuple({}) -> true; true -> false end end, + "if is_tuple({}) -> true; true -> false end.", true), + ?line check(fun() -> if tuple({}) -> true; true -> false end end, + "if tuple({}) -> true; true -> false end.", true), + ?line check(fun() -> if is_pid(self()) -> true; true -> false end end, + "if is_pid(self()) -> true; true -> false end.", true), + ?line check(fun() -> if pid(self()) -> true; true -> false end end, + "if pid(self()) -> true; true -> false end.", true), + ?line check(fun() -> R = make_ref(), if is_reference(R) -> true; + true -> false end end, + "begin R = make_ref(), if is_reference(R) -> true;" + "true -> false end end.", true), + ?line check(fun() -> R = make_ref(), if reference(R) -> true; + true -> false end end, + "begin R = make_ref(), if reference(R) -> true;" + "true -> false end end.", true), + ?line check(fun() -> if is_port(a) -> true; true -> false end end, + "if is_port(a) -> true; true -> false end.", false), + ?line check(fun() -> if port(a) -> true; true -> false end end, + "if port(a) -> true; true -> false end.", false), + ?line check(fun() -> if is_function(a) -> true; true -> false end end, + "if is_function(a) -> true; true -> false end.", false), + ?line check(fun() -> if function(a) -> true; true -> false end end, + "if function(a) -> true; true -> false end.", false), + ?line check(fun() -> if is_binary(<<>>) -> true; true -> false end end, + "if is_binary(<<>>) -> true; true -> false end.", true), + ?line check(fun() -> if binary(<<>>) -> true; true -> false end end, + "if binary(<<>>) -> true; true -> false end.", true), + ?line check(fun() -> if is_integer(a) == true -> yes; + true -> no end end, + "if is_integer(a) == true -> yes; + true -> no end.", + no), + ?line check(fun() -> if [] -> true; true -> false end end, + "if [] -> true; true -> false end.", false), + ?line error_check("if lists:member(1,[1]) -> true; true -> false end.", + illegal_guard_expr), + ?line error_check("if false -> true end.", if_clause), + ?line check(fun() -> if a+b -> true; true -> false end end, + "if a + b -> true; true -> false end.", false), + ?line check(fun() -> if + b -> true; true -> false end end, + "if + b -> true; true -> false end.", false), + ?line error_check("case foo of bar -> true end.", {case_clause,foo}), + ?line error_check("case 4 of 2+a -> true; _ -> false end.", + illegal_pattern), + ?line error_check("case 4 of +a -> true; _ -> false end.", + illegal_pattern), + ?line check(fun() -> case a of + X when X == b -> one; + X when X == a -> two + end end, + "begin case a of + X when X == b -> one; + X when X == a -> two + end end.", two), + ?line error_check("3 = 4.", {badmatch,4}), + ?line error_check("a = 3.", {badmatch,3}), + %% ?line error_check("3.1 = 2.7.",{badmatch,2.7}), + ?line error_check("$c = 4.", {badmatch,4}), + ?line check(fun() -> $c = $c end, "$c = $c.", $c), + ?line check(fun() -> _ = bar end, "_ = bar.", bar), + ?line check(fun() -> A = 14, A = 14 end, + "begin A = 14, A = 14 end.", 14), + ?line error_check("begin A = 14, A = 16 end.", {badmatch,16}), + ?line error_check("\"hej\" = \"san\".", {badmatch,"san"}), + ?line check(fun() -> "hej" = "hej" end, + "\"hej\" = \"hej\".", "hej"), + ?line error_check("[] = [a].", {badmatch,[a]}), + ?line check(fun() -> [] = [] end, "[] = [].", []), + ?line error_check("[a] = [].", {badmatch,[]}), + ?line error_check("{a,b} = 34.", {badmatch,34}), + ?line check(fun() -> <<X:7>> = <<8:7>>, X end, + "begin <<X:7>> = <<8:7>>, X end.", 8), + ?line error_check("<<34:32>> = \"hej\".", {badmatch,"hej"}), + ?line check(fun() -> trunc((1 * 3 div 3 + 4 - 3) / 1) rem 2 end, + "begin trunc((1 * 3 div 3 + 4 - 3) / 1) rem 2 end.", 0), + ?line check(fun() -> (2#101 band 2#10101) bor (2#110 bxor 2#010) end, + "(2#101 band 2#10101) bor (2#110 bxor 2#010).", 5), + ?line check(fun() -> (2#1 bsl 4) + (2#10000 bsr 3) end, + "(2#1 bsl 4) + (2#10000 bsr 3).", 18), + ?line check(fun() -> ((1<3) and ((1 =:= 2) or (1 =/= 2))) xor (1=<2) end, + "((1<3) and ((1 =:= 2) or (1 =/= 2))) xor (1=<2).", false), + ?line check(fun() -> (a /= b) or (2 > 4) or (3 >= 3) end, + "(a /= b) or (2 > 4) or (3 >= 3).", true), + ?line check(fun() -> "hej" ++ "san" =/= "hejsan" -- "san" end, + "\"hej\" ++ \"san\" =/= \"hejsan\" -- \"san\".", true), + ?line check(fun() -> (bnot 1) < -0 end, "(bnot (+1)) < -0.", true), + ok. + +unary_plus(doc) -> + ["OTP-4929. Unary plus rejects non-numbers."]; +unary_plus(suite) -> + []; +unary_plus(Config) when is_list(Config) -> + ?line check(fun() -> F = fun(X) -> + X end, + true = -1 == F(-1) end, + "begin F = fun(X) -> + X end," + " true = -1 == F(-1) end.", true, ['F'], none, none), + ?line error_check("+a.", badarith), + ok. + +apply_atom(doc) -> + ["OTP-5064. Can no longer apply atoms."]; +apply_atom(suite) -> + []; +apply_atom(Config) when is_list(Config) -> + ?line error_check("[X || X <- [[1],[2]], + begin L = length, L(X) =:= 1 end].", + {badfun,length}), + ok. + +otp_5269(doc) -> + ["OTP-5269. Bugs in the bit syntax."]; +otp_5269(suite) -> + []; +otp_5269(Config) when is_list(Config) -> + ?line check(fun() -> L = 8, + F = fun(<<A:L,B:A>>) -> B end, + F(<<16:8, 7:16>>) + end, + "begin + L = 8, F = fun(<<A:L,B:A>>) -> B end, F(<<16:8, 7:16>>) + end.", + 7), + ?line check(fun() -> L = 8, + F = fun(<<L:L,B:L>>) -> B end, + F(<<16:8, 7:16>>) + end, + "begin + L = 8, F = fun(<<L:L,B:L>>) -> B end, F(<<16:8, 7:16>>) + end.", + 7), + ?line check(fun() -> L = 8, <<A:L,B:A>> = <<16:8, 7:16>>, B end, + "begin L = 8, <<A:L,B:A>> = <<16:8, 7:16>>, B end.", + 7), + ?line error_check("begin L = 8, <<L:L,B:L>> = <<16:8, 7:16>> end.", + {badmatch,<<16:8,7:16>>}), + + ?line error_check("begin <<L:16,L:L>> = <<16:16,8:16>>, L end.", + {badmatch, <<16:16,8:16>>}), + ?line check(fun() -> U = 8, (fun(<<U:U>>) -> U end)(<<32:8>>) end, + "begin U = 8, (fun(<<U:U>>) -> U end)(<<32:8>>) end.", + 32), + ?line check(fun() -> U = 8, [U || <<U:U>> <- [<<32:8>>]] end, + "begin U = 8, [U || <<U:U>> <- [<<32:8>>]] end.", + [32]), + ?line error_check("(fun({3,<<A:32,A:32>>}) -> a end) + ({3,<<17:32,19:32>>}).", + function_clause), + ?line check(fun() -> [X || <<A:8, + B:A>> <- [<<16:8,19:16>>], + <<X:8>> <- [<<B:8>>]] end, + "[X || <<A:8, + B:A>> <- [<<16:8,19:16>>], + <<X:8>> <- [<<B:8>>]].", + [19]), + ok. + +otp_6539(doc) -> + ["OTP-6539. try/catch bugs."]; +otp_6539(suite) -> + []; +otp_6539(Config) when is_list(Config) -> + ?line check(fun() -> + F = fun(A,B) -> + try A+B + catch _:_ -> dontthinkso + end + end, + lists:zipwith(F, [1,2], [2,3]) + end, + "begin + F = fun(A,B) -> + try A+B + catch _:_ -> dontthinkso + end + end, + lists:zipwith(F, [1,2], [2,3]) + end.", + [3, 5]), + ok. + +otp_6543(doc) -> + ["OTP-6543. bitlevel binaries."]; +otp_6543(suite) -> + []; +otp_6543(Config) when is_list(Config) -> + ?line check(fun() -> + << <<X>> || <<X>> <- [1,2,3] >> + end, + "<< <<X>> || <<X>> <- [1,2,3] >>.", + <<>>), + ?line check(fun() -> + << <<X>> || X <- [1,2,3] >> + end, + "<< <<X>> || X <- [1,2,3] >>.", + <<1,2,3>>), + ?line check(fun() -> + << <<X:8>> || <<X:2>> <= <<"hej">> >> + end, + "<< <<X:8>> || <<X:2>> <= <<\"hej\">> >>.", + <<1,2,2,0,1,2,1,1,1,2,2,2>>), + ?line check(fun() -> + << <<X:8>> || + <<65,X:4>> <= <<65,7:4,65,3:4,66,8:4>> >> + end, + "<< <<X:8>> || + <<65,X:4>> <= <<65,7:4,65,3:4,66,8:4>> >>.", + <<7,3>>), + ?line check(fun() -> <<34:18/big>> end, + "<<34:18/big>>.", + <<0,8,2:2>>), + ?line check(fun() -> <<34:18/big-unit:2>> end, + "<<34:18/big-unit:2>>.", + <<0,0,0,2,2:4>>), + ?line check(fun() -> <<34:18/little>> end, + "<<34:18/little>>.", + <<34,0,0:2>>), + ?line case eval_string("<<34:18/native>>.") of + <<0,8,2:2>> -> ok; + <<34,0,0:2>> -> ok + end, + ?line check(fun() -> <<34:18/big-signed>> end, + "<<34:18/big-signed>>.", + <<0,8,2:2>>), + ?line check(fun() -> <<34:18/little-signed>> end, + "<<34:18/little-signed>>.", + <<34,0,0:2>>), + ?line case eval_string("<<34:18/native-signed>>.") of + <<0,8,2:2>> -> ok; + <<34,0,0:2>> -> ok + end, + ?line check(fun() -> <<34:18/big-unsigned>> end, + "<<34:18/big-unsigned>>.", + <<0,8,2:2>>), + ?line check(fun() -> <<34:18/little-unsigned>> end, + "<<34:18/little-unsigned>>.", + <<34,0,0:2>>), + ?line case eval_string("<<34:18/native-unsigned>>.") of + <<0,8,2:2>> -> ok; + <<34,0,0:2>> -> ok + end, + ?line check(fun() -> <<3.14:32/float-big>> end, + "<<3.14:32/float-big>>.", + <<64,72,245,195>>), + ?line check(fun() -> <<3.14:32/float-little>> end, + "<<3.14:32/float-little>>.", + <<195,245,72,64>>), + ?line case eval_string("<<3.14:32/float-native>>.") of + <<64,72,245,195>> -> ok; + <<195,245,72,64>> -> ok + end, + ?line error_check("<<(<<17,3:2>>)/binary>>.", badarg), + ?line check(fun() -> <<(<<17,3:2>>)/bitstring>> end, + "<<(<<17,3:2>>)/bitstring>>.", + <<17,3:2>>), + ?line check(fun() -> <<(<<17,3:2>>):10/bitstring>> end, + "<<(<<17,3:2>>):10/bitstring>>.", + <<17,3:2>>), + ?line check(fun() -> <<<<344:17>>/binary-unit:17>> end, + "<<<<344:17>>/binary-unit:17>>.", + <<344:17>>), + + ?line check(fun() -> <<X:18/big>> = <<34:18/big>>, X end, + "begin <<X:18/big>> = <<34:18/big>>, X end.", + 34), + ?line check(fun() -> <<X:18/big-unit:2>> = <<34:18/big-unit:2>>, X end, + "begin <<X:18/big-unit:2>> = <<34:18/big-unit:2>>, X end.", + 34), + ?line check(fun() -> <<X:18/little>> = <<34:18/little>>, X end, + "begin <<X:18/little>> = <<34:18/little>>, X end.", + 34), + ?line check(fun() -> <<X:18/native>> = <<34:18/native>>, X end, + "begin <<X:18/native>> = <<34:18/native>>, X end.", + 34), + ?line check(fun() -> <<X:18/big-signed>> = <<34:18/big-signed>>, X end, + "begin <<X:18/big-signed>> = <<34:18/big-signed>>, X end.", + 34), + ?line check(fun() -> <<X:18/little-signed>> = <<34:18/little-signed>>, + X end, + "begin <<X:18/little-signed>> = <<34:18/little-signed>>, + X end.", + 34), + ?line check(fun() -> <<X:18/native-signed>> = <<34:18/native-signed>>, + X end, + "begin <<X:18/native-signed>> = <<34:18/native-signed>>, + X end.", + 34), + ?line check(fun() -> <<X:18/big-unsigned>> = <<34:18/big-unsigned>>, + X end, + "begin <<X:18/big-unsigned>> = <<34:18/big-unsigned>>, + X end.", + 34), + ?line check(fun() -> + <<X:18/little-unsigned>> = <<34:18/little-unsigned>>, + X end, + "begin <<X:18/little-unsigned>> = <<34:18/little-unsigned>>, + X end.", + 34), + ?line check(fun() -> + <<X:18/native-unsigned>> = <<34:18/native-unsigned>>, + X end, + "begin <<X:18/native-unsigned>> = <<34:18/native-unsigned>>, + X end.", + 34), + ?line check(fun() -> <<X:32/float-big>> = <<2.0:32/float-big>>, X end, + "begin <<X:32/float-big>> = <<2.0:32/float-big>>, + X end.", + 2.0), + ?line check(fun() -> <<X:32/float-little>> = <<2.0:32/float-little>>, + X end, + "begin <<X:32/float-little>> = <<2.0:32/float-little>>, + X end.", + 2.0), + ?line check(fun() -> <<X:32/float-native>> = <<2.0:32/float-native>>, + X end, + "begin <<X:32/float-native>> = <<2.0:32/float-native>>, + X end.", + 2.0), + + ?line check( + fun() -> + [X || <<"hej",X:8>> <= <<"hej",8,"san",9,"hej",17,"hej">>] + end, + "[X || <<\"hej\",X:8>> <= + <<\"hej\",8,\"san\",9,\"hej\",17,\"hej\">>].", + [8,17]), + ?line check( + fun() -> + L = 8, << <<B:32>> || <<L:L,B:L>> <= <<16:8, 7:16>> >> + end, + "begin L = 8, << <<B:32>> || <<L:L,B:L>> <= <<16:8, 7:16>> >> + end.", + <<0,0,0,7>>), + %% Test the Value part of a binary segment. + %% "Old" bugs have been fixed (partial_eval is called on Value). + ?line check(fun() -> [ 3 || <<17/float>> <= <<17.0/float>>] end, + "[ 3 || <<17/float>> <= <<17.0/float>>].", + [3]), + ?line check(fun() -> [ 3 || <<17/float>> <- [<<17.0/float>>]] end, + "[ 3 || <<17/float>> <- [<<17.0/float>>]].", + [3]), + ?line check(fun() -> [ X || <<17/float,X:3>> <= <<17.0/float,2:3>>] end, + "[ X || <<17/float,X:3>> <= <<17.0/float,2:3>>].", + [2]), + ?line check(fun() -> + [ foo || <<(1 bsl 1023)/float>> <= <<(1 bsl 1023)/float>>] + end, + "[ foo || <<(1 bsl 1023)/float>> <= <<(1 bsl 1023)/float>>].", + [foo]), + ?line check(fun() -> + [ foo || <<(1 bsl 1023)/float>> <- [<<(1 bsl 1023)/float>>]] + end, + "[ foo || <<(1 bsl 1023)/float>> <- [<<(1 bsl 1023)/float>>]].", + [foo]), + ?line error_check("[ foo || <<(1 bsl 1024)/float>> <- + [<<(1 bsl 1024)/float>>]].", + badarg), + ?line check(fun() -> + [ foo || <<(1 bsl 1024)/float>> <- [<<(1 bsl 1023)/float>>]] + end, + "[ foo || <<(1 bsl 1024)/float>> <- + [<<(1 bsl 1023)/float>>]].", + []), + ?line check(fun() -> + [ foo || <<(1 bsl 1024)/float>> <= <<(1 bsl 1023)/float>>] + end, + "[ foo || <<(1 bsl 1024)/float>> <= + <<(1 bsl 1023)/float>>].", + []), + ?line check(fun() -> + L = 8, + [{L,B} || <<L:L,B:L/float>> <= <<32:8,7:32/float>>] + end, + "begin L = 8, + [{L,B} || <<L:L,B:L/float>> <= <<32:8,7:32/float>>] + end.", + [{32,7.0}]), + ?line check(fun() -> + L = 8, + [{L,B} || <<L:L,B:L/float>> <- [<<32:8,7:32/float>>]] + end, + "begin L = 8, + [{L,B} || <<L:L,B:L/float>> <- [<<32:8,7:32/float>>]] + end.", + [{32,7.0}]), + ?line check(fun() -> + [foo || <<"s">> <= <<"st">>] + end, + "[foo || <<\"s\">> <= <<\"st\">>].", + [foo]), + ?line check(fun() -> <<_:32>> = <<17:32>> end, + "<<_:32>> = <<17:32>>.", + <<17:32>>), + ?line check(fun() -> [foo || <<_:32>> <= <<17:32,20:32>>] end, + "[foo || <<_:32>> <= <<17:32,20:32>>].", + [foo,foo]), + + ?line check(fun() -> << <<X:32>> || X <- [1,2,3], X > 1 >> end, + "<< <<X:32>> || X <- [1,2,3], X > 1 >>.", + <<0,0,0,2,0,0,0,3>>), + ?line error_check("[X || <<X>> <= [a,b]].",{bad_generator,[a,b]}), + ok. + +otp_6787(doc) -> + ["OTP-6787. bitlevel binaries."]; +otp_6787(suite) -> + []; +otp_6787(Config) when is_list(Config) -> + ?line check( + fun() -> <<16:(1024*1024)>> = <<16:(1024*1024)>> end, + "<<16:(1024*1024)>> = <<16:(1024*1024)>>.", + <<16:1048576>>), + ok. + +otp_6977(doc) -> + ["OTP-6977. ++ bug."]; +otp_6977(suite) -> + []; +otp_6977(Config) when is_list(Config) -> + ?line check( + fun() -> (fun([$X] ++ _) -> ok end)("X") end, + "(fun([$X] ++ _) -> ok end)(\"X\").", + ok), + ok. + +otp_7550(doc) -> + ["OTP-7550. Support for UTF-8, UTF-16, UTF-32."]; +otp_7550(Config) when is_list(Config) -> + + %% UTF-8. + ?line check( + fun() -> <<65>> = <<65/utf8>> end, + "<<65>> = <<65/utf8>>.", + <<65>>), + ?line check( + fun() -> <<350/utf8>> = <<197,158>> end, + "<<350/utf8>> = <<197,158>>.", + <<197,158>>), + ?line check( + fun() -> <<$b,$j,$\303,$\266,$r,$n>> = <<"bj\366rn"/utf8>> end, + "<<$b,$j,$\303,$\266,$r,$n>> = <<\"bj\366rn\"/utf8>>.", + <<$b,$j,$\303,$\266,$r,$n>>), + + %% UTF-16. + ?line check( + fun() -> <<0,65>> = <<65/utf16>> end, + "<<0,65>> = <<65/utf16>>.", + <<0,65>>), + ?line check( + fun() -> <<16#D8,16#08,16#DF,16#45>> = <<16#12345/utf16>> end, + "<<16#D8,16#08,16#DF,16#45>> = <<16#12345/utf16>>.", + <<16#D8,16#08,16#DF,16#45>>), + ?line check( + fun() -> <<16#08,16#D8,16#45,16#DF>> = <<16#12345/little-utf16>> end, + "<<16#08,16#D8,16#45,16#DF>> = <<16#12345/little-utf16>>.", + <<16#08,16#D8,16#45,16#DF>>), + + ?line check( + fun() -> <<350/utf16>> = <<1,94>> end, + "<<350/utf16>> = <<1,94>>.", + <<1,94>>), + ?line check( + fun() -> <<350/little-utf16>> = <<94,1>> end, + "<<350/little-utf16>> = <<94,1>>.", + <<94,1>>), + ?line check( + fun() -> <<16#12345/utf16>> = <<16#D8,16#08,16#DF,16#45>> end, + "<<16#12345/utf16>> = <<16#D8,16#08,16#DF,16#45>>.", + <<16#D8,16#08,16#DF,16#45>>), + ?line check( + fun() -> <<16#12345/little-utf16>> = <<16#08,16#D8,16#45,16#DF>> end, + "<<16#12345/little-utf16>> = <<16#08,16#D8,16#45,16#DF>>.", + <<16#08,16#D8,16#45,16#DF>>), + + %% UTF-32. + ?line check( + fun() -> <<16#12345/utf32>> = <<16#0,16#01,16#23,16#45>> end, + "<<16#12345/utf32>> = <<16#0,16#01,16#23,16#45>>.", + <<16#0,16#01,16#23,16#45>>), + ?line check( + fun() -> <<16#0,16#01,16#23,16#45>> = <<16#12345/utf32>> end, + "<<16#0,16#01,16#23,16#45>> = <<16#12345/utf32>>.", + <<16#0,16#01,16#23,16#45>>), + ?line check( + fun() -> <<16#12345/little-utf32>> = <<16#45,16#23,16#01,16#00>> end, + "<<16#12345/little-utf32>> = <<16#45,16#23,16#01,16#00>>.", + <<16#45,16#23,16#01,16#00>>), + ?line check( + fun() -> <<16#12345/little-utf32>> end, + "<<16#12345/little-utf32>>.", + <<16#45,16#23,16#01,16#00>>), + + %% Mixed. + ?line check( + fun() -> <<16#41,16#12345/utf32,16#0391:16,16#2E:8>> end, + "<<16#41,16#12345/utf32,16#0391:16,16#2E:8>>.", + <<16#41,16#00,16#01,16#23,16#45,16#03,16#91,16#2E>>), + ok. + + +otp_8133(doc) -> + ["OTP-8133. Bit comprehension bug."]; +otp_8133(suite) -> + []; +otp_8133(Config) when is_list(Config) -> + ?line check( + fun() -> + E = fun(N) -> + if + is_integer(N) -> <<N/integer>>; + true -> throw(foo) + end + end, + try << << (E(V))/binary >> || V <- [1,2,3,a] >> + catch foo -> ok + end + end, + "begin + E = fun(N) -> + if is_integer(N) -> <<N/integer>>; + true -> throw(foo) + end + end, + try << << (E(V))/binary >> || V <- [1,2,3,a] >> + catch foo -> ok + end + end.", + ok), + ?line check( + fun() -> + E = fun(N) -> + if + is_integer(N) -> <<N/integer>>; + true -> erlang:error(foo) + end + end, + try << << (E(V))/binary >> || V <- [1,2,3,a] >> + catch error:foo -> ok + end + end, + "begin + E = fun(N) -> + if is_integer(N) -> <<N/integer>>; + true -> erlang:error(foo) + end + end, + try << << (E(V))/binary >> || V <- [1,2,3,a] >> + catch error:foo -> ok + end + end.", + ok), + ok. + +funs(doc) -> + ["Simple cases, just to cover some code."]; +funs(suite) -> + []; +funs(Config) when is_list(Config) -> + do_funs(none, none), + do_funs(lfh(), none), + do_funs(lfh(), efh()), + + ?line error_check("nix:foo().", {access_not_allowed,nix}, lfh(), efh()), + ?line error_check("bar().", undef, none, none), + + ?line check(fun() -> F1 = fun(F,N) -> ?MODULE:count_down(F, N) end, + F1(F1, 1000) end, + "begin F1 = fun(F,N) -> count_down(F, N) end," + "F1(F1,1000) end.", + 0, ['F1'], lfh(), none), + + ?line check(fun() -> F1 = fun(F,N) -> ?MODULE:count_down(F, N) end, + F1(F1, 1000) end, + "begin F1 = fun(F,N) -> count_down(F, N) end," + "F1(F1,1000) end.", + 0, ['F1'], lfh_value(), none), + + ?line check(fun() -> F1 = fun(F,N) -> ?MODULE:count_down(F, N) end, + F1(F1, 1000) end, + "begin F1 = fun(F,N) -> count_down(F, N) end," + "F1(F1,1000) end.", + 0, ['F1'], lfh_value_extra(), none), + + ?line check(fun() -> F1 = fun(F,N) -> ?MODULE:count_down(F, N) end, + F1(F1, 1000) end, + "begin F1 = fun(F,N) -> count_down(F, N) end," + "F1(F1,1000) end.", + 0, ['F1'], {?MODULE,local_func_value}, none), + %% This is not documented, and only for backward compatibility (good!). + B0 = erl_eval:new_bindings(), + ?line check(fun() -> is_function(?MODULE:count_down_fun()) end, + "begin is_function(count_down_fun()) end.", + true, [], {?MODULE,local_func,[B0]},none), + + EF = fun({timer,sleep}, As) when length(As) == 1 -> exit({got_it,sleep}); + ({M,F}, As) -> apply(M, F, As) + end, + EFH = {value, EF}, + ?line error_check("apply(timer, sleep, [1]).", got_it, none, EFH), + ?line error_check("begin F = fun(T) -> timer:sleep(T) end,F(1) end.", + got_it, none, EFH), + ?line error_check("fun c/1.", undef), + ?line error_check("fun a:b/0().", undef), + + MaxArgs = 20, + ?line [true] = + lists:usort([run_many_args(SAs) || SAs <- many_args(MaxArgs)]), + ?line {'EXIT',{{argument_limit,_},_}} = + (catch run_many_args(many_args1(MaxArgs+1))), + ok. + +run_many_args({S, As}) -> + apply(eval_string(S), As) =:= As. + +many_args(N) -> + [many_args1(I) || I <- lists:seq(1, N)]. + +many_args1(N) -> + F = fun(L, P) -> + tl(lists:flatten([","++P++integer_to_list(E) || E <- L])) + end, + L = lists:seq(1, N), + T = F(L, "V"), + S = lists:flatten(io_lib:format("fun(~s) -> [~s] end.", [T, T])), + {S, L}. + +do_funs(LFH, EFH) -> + %% LFH is not really used by these examples... + + %% These tests do not prove that tail recursive functions really + %% work (that the process does not grow); one should also run them + %% manually with 1000 replaced by 1000000. + + M = atom_to_list(?MODULE), + ?line check(fun() -> F1 = fun(F,N) -> ?MODULE:count_down(F, N) end, + F1(F1, 1000) end, + concat(["begin F1 = fun(F,N) -> ", M, + ":count_down(F, N) end, F1(F1,1000) end."]), + 0, ['F1'], LFH, EFH), + ?line check(fun() -> F1 = fun(F,N) -> apply(?MODULE,count_down,[F,N]) + end, F1(F1, 1000) end, + concat(["begin F1 = fun(F,N) -> apply(", M, + ",count_down,[F, N]) end, F1(F1,1000) end."]), + 0, ['F1'], LFH, EFH), + ?line check(fun() -> F1 = fun(F,N) -> {?MODULE,count_down}(F,N) + end, F1(F1, 1000) end, + concat(["begin F1 = fun(F,N) -> {", M, + ",count_down}(F, N) end, F1(F1,1000) end."]), + 0, ['F1'], LFH, EFH), + ?line check(fun() -> F = fun(F,N) when N > 0 -> apply(F,[F,N-1]); + (_F,0) -> ok end, + F(F, 1000) + end, + "begin F = fun(F,N) when N > 0 -> apply(F,[F,N-1]);" + "(_F,0) -> ok end," + "F(F, 1000) end.", + ok, ['F'], LFH, EFH), + ?line check(fun() -> F = fun(F,N) when N > 0 -> + apply(erlang,apply,[F,[F,N-1]]); + (_F,0) -> ok end, + F(F, 1000) + end, + "begin F = fun(F,N) when N > 0 ->" + "apply(erlang,apply,[F,[F,N-1]]);" + "(_F,0) -> ok end," + "F(F, 1000) end.", + ok, ['F'], LFH, EFH), + ?line check(fun() -> F = count_down_fun(), + SF = fun(SF, F1, N) -> F(SF, F1, N) end, + SF(SF, F, 1000) end, + concat(["begin F = ", M, ":count_down_fun()," + "SF = fun(SF, F1, N) -> F(SF, F1, N) end," + "SF(SF, F, 1000) end."]), + ok, ['F','SF'], LFH, EFH), + + + ?line check(fun() -> F = fun(X) -> A = 1+X, {X,A} end, + true = {2,3} == F(2) end, + "begin F = fun(X) -> A = 1+X, {X,A} end, + true = {2,3} == F(2) end.", true, ['F'], LFH, EFH), + ?line check(fun() -> F = fun(X) -> {erlang,'+'}(X,2) end, + true = 3 == F(1) end, + "begin F = fun(X) -> {erlang,'+'}(X,2) end," + " true = 3 == F(1) end.", true, ['F'], + LFH, EFH), + ?line check(fun() -> F = fun(X) -> byte_size(X) end, + ?MODULE:do_apply(F,<<"hej">>) end, + concat(["begin F = fun(X) -> size(X) end,", + M,":do_apply(F,<<\"hej\">>) end."]), + 3, ['F'], LFH, EFH), + + ?line check(fun() -> F1 = fun(X, Z) -> {X,Z} end, + Z = 5, + F2 = fun(X, Y) -> F1(Z,{X,Y}) end, + F3 = fun(X, Y) -> {a,F1(Z,{X,Y})} end, + {5,{x,y}} = F2(x,y), + {a,{5,{y,x}}} = F3(y,x), + {5,{5,y}} = F2(Z,y), + true = {5,{x,5}} == F2(x,Z) end, + "begin F1 = fun(X, Z) -> {X,Z} end, + Z = 5, + F2 = fun(X, Y) -> F1(Z,{X,Y}) end, + F3 = fun(X, Y) -> {a,F1(Z,{X,Y})} end, + {5,{x,y}} = F2(x,y), + {a,{5,{y,x}}} = F3(y,x), + {5,{5,y}} = F2(Z,y), + true = {5,{x,5}} == F2(x,Z) end.", + true, ['F1','Z','F2','F3'], LFH, EFH), + ?line check(fun() -> F = fun(X) -> byte_size(X) end, + F2 = fun(Y) -> F(Y) end, + ?MODULE:do_apply(F2,<<"hej">>) end, + concat(["begin F = fun(X) -> size(X) end,", + "F2 = fun(Y) -> F(Y) end,", + M,":do_apply(F2,<<\"hej\">>) end."]), + 3, ['F','F2'], LFH, EFH), + ?line check(fun() -> Z = 5, F = fun(X) -> {Z,X} end, + F2 = fun(Z) -> F(Z) end, F2(3) end, + "begin Z = 5, F = fun(X) -> {Z,X} end, + F2 = fun(Z) -> F(Z) end, F2(3) end.", + {5,3},['F','F2','Z'], LFH, EFH), + ?line check(fun() -> F = fun(Z) -> Z end, + F2 = fun(X) -> F(X), Z = {X,X}, Z end, + {1,1} = F2(1), Z = 7, Z end, + "begin F = fun(Z) -> Z end, + F2 = fun(X) -> F(X), Z = {X,X}, Z end, + {1,1} = F2(1), Z = 7, Z end.", 7, ['F','F2','Z'], + LFH, EFH), + ?line check(fun() -> F = fun(F, N) -> [?MODULE:count_down(F,N) || X <-[1]] + end, F(F,2) end, + concat(["begin F = fun(F, N) -> [", M, + ":count_down(F,N) || X <-[1]] end, F(F,2) end."]), + [[[0]]], ['F'], LFH, EFH), + ok. + +count_down(F, N) when N > 0 -> + F(F, N-1); +count_down(_F, N) -> + N. + +count_down_fun() -> + fun(SF,F,N) when N > 0 -> SF(SF,F,N-1); + (_SF,_F,_N) -> ok + end. + +do_apply(F, V) -> + F(V). + +lfh() -> + {eval, fun(F, As, Bs) -> local_func(F, As, Bs) end}. + +local_func(F, As0, Bs0) when is_atom(F) -> + {As,Bs} = erl_eval:expr_list(As0, Bs0, {eval,lfh()}), + case erlang:function_exported(?MODULE, F, length(As)) of + true -> + {value,apply(?MODULE, F, As),Bs}; + false -> + {value,apply(shell_default, F, As),Bs} + end. + +lfh_value_extra() -> + %% Not documented. + {value, fun(F, As) -> local_func_value(F, As) end, []}. + +lfh_value() -> + {value, fun(F, As) -> local_func_value(F, As) end}. + +local_func_value(F, As) when is_atom(F) -> + case erlang:function_exported(?MODULE, F, length(As)) of + true -> + apply(?MODULE, F, As); + false -> + apply(shell_default, F, As) + end. + +efh() -> + {value, fun(F, As) -> external_func(F, As) end}. + +external_func({M,_}, _As) when M == nix -> + exit({{access_not_allowed,M},[mfa]}); +external_func(F, As) when is_function(F) -> + apply(F, As); +external_func({M,F}, As) -> + apply(M, F, As). + + + +try_catch(doc) -> + ["Test try-of-catch-after-end statement"]; +try_catch(suite) -> + []; +try_catch(Config) when is_list(Config) -> + %% Match in of with catch + ?line check(fun() -> try 1 of 1 -> 2 catch _:_ -> 3 end end, + "try 1 of 1 -> 2 catch _:_ -> 3 end.", 2), + ?line check(fun() -> try 1 of 1 -> 2; 3 -> 4 catch _:_ -> 5 end end, + "try 1 of 1 -> 2; 3 -> 4 catch _:_ -> 5 end.", 2), + ?line check(fun() -> try 3 of 1 -> 2; 3 -> 4 catch _:_ -> 5 end end, + "try 3 of 1 -> 2; 3 -> 4 catch _:_ -> 5 end.", 4), + %% Just after + ?line check(fun () -> X = try 1 after put(try_catch, 2) end, + {X,get(try_catch)} end, + "begin X = try 1 after put(try_catch, 2) end, " + "{X,get(try_catch)} end.", {1,2}), + %% Match in of with after + ?line check(fun() -> X = try 1 of 1 -> 2 after put(try_catch, 3) end, + {X,get(try_catch)} end, + "begin X = try 1 of 1 -> 2 after put(try_catch, 3) end, " + "{X,get(try_catch)} end.", {2,3}), + ?line check(fun() -> X = try 1 of 1 -> 2; 3 -> 4 + after put(try_catch, 5) end, + {X,get(try_catch)} end, + "begin X = try 1 of 1 -> 2; 3 -> 4 " + " after put(try_catch, 5) end, " + " {X,get(try_catch)} end.", {2,5}), + ?line check(fun() -> X = try 3 of 1 -> 2; 3 -> 4 + after put(try_catch, 5) end, + {X,get(try_catch)} end, + "begin X = try 3 of 1 -> 2; 3 -> 4 " + " after put(try_catch, 5) end, " + " {X,get(try_catch)} end.", {4,5}), + %% Nomatch in of + ?line error_check("try 1 of 2 -> 3 catch _:_ -> 4 end.", + {try_clause,1}), + %% Nomatch in of with after + ?line check(fun () -> {'EXIT',{{try_clause,1},_}} = + begin catch try 1 of 2 -> 3 + after put(try_catch, 4) end end, + get(try_catch) end, + "begin {'EXIT',{{try_clause,1},_}} = " + " begin catch try 1 of 2 -> 3 " + " after put(try_catch, 4) end end, " + " get(try_catch) end. ", 4), + %% Exception in try + ?line check(fun () -> try 1=2 catch error:{badmatch,2} -> 3 end end, + "try 1=2 catch error:{badmatch,2} -> 3 end.", 3), + ?line check(fun () -> try 1=2 of 3 -> 4 + catch error:{badmatch,2} -> 5 end end, + "try 1=2 of 3 -> 4 " + "catch error:{badmatch,2} -> 5 end.", 5), + %% Exception in try with after + ?line check(fun () -> X = try 1=2 + catch error:{badmatch,2} -> 3 + after put(try_catch, 4) end, + {X,get(try_catch)} end, + "begin X = try 1=2 " + " catch error:{badmatch,2} -> 3 " + " after put(try_catch, 4) end, " + " {X,get(try_catch)} end. ", {3,4}), + ?line check(fun () -> X = try 1=2 of 3 -> 4 + catch error:{badmatch,2} -> 5 + after put(try_catch, 6) end, + {X,get(try_catch)} end, + "begin X = try 1=2 of 3 -> 4" + " catch error:{badmatch,2} -> 5 " + " after put(try_catch, 6) end, " + " {X,get(try_catch)} end. ", {5,6}), + %% Uncaught exception + ?line error_check("try 1=2 catch error:undefined -> 3 end. ", + {badmatch,2}), + ?line error_check("try 1=2 of 3 -> 4 catch error:undefined -> 5 end. ", + {badmatch,2}), + %% Uncaught exception with after + ?line check(fun () -> {'EXIT',{{badmatch,2},_}} = + begin catch try 1=2 + after put(try_catch, 3) end end, + get(try_catch) end, + "begin {'EXIT',{{badmatch,2},_}} = " + " begin catch try 1=2 " + " after put(try_catch, 3) end end, " + " get(try_catch) end. ", 3), + ?line check(fun () -> {'EXIT',{{badmatch,2},_}} = + begin catch try 1=2 of 3 -> 4 + after put(try_catch, 5) end end, + get(try_catch) end, + "begin {'EXIT',{{badmatch,2},_}} = " + " begin catch try 1=2 of 3 -> 4" + " after put(try_catch, 5) end end, " + " get(try_catch) end. ", 5), + ?line check(fun () -> {'EXIT',{{badmatch,2},_}} = + begin catch try 1=2 catch error:undefined -> 3 + after put(try_catch, 4) end end, + get(try_catch) end, + "begin {'EXIT',{{badmatch,2},_}} = " + " begin catch try 1=2 catch error:undefined -> 3 " + " after put(try_catch, 4) end end, " + " get(try_catch) end. ", 4), + ?line check(fun () -> {'EXIT',{{badmatch,2},_}} = + begin catch try 1=2 of 3 -> 4 + catch error:undefined -> 5 + after put(try_catch, 6) end end, + get(try_catch) end, + "begin {'EXIT',{{badmatch,2},_}} = " + " begin catch try 1=2 of 3 -> 4 " + " catch error:undefined -> 5 " + " after put(try_catch, 6) end end, " + " get(try_catch) end. ", 6), + ok. + + +eval_expr_5(doc) -> + ["(OTP-7933)"]; +eval_expr_5(suite) -> + []; +eval_expr_5(Config) when is_list(Config) -> + ?line {ok,Tokens ,_} = + erl_scan:string("if a+4 == 4 -> yes; true -> no end. "), + ?line {ok, [Expr]} = erl_parse:parse_exprs(Tokens), + ?line {value, no, []} = erl_eval:expr(Expr, [], none, none, none), + ?line no = erl_eval:expr(Expr, [], none, none, value), + try + erl_eval:expr(Expr, [], none, none, 4711), + ?line function_clause = should_never_reach_here + catch + error:function_clause -> + ok + end. + +%% Check the string in different contexts: as is; in fun; from compiled code. +check(F, String, Result) -> + check1(F, String, Result), + FunString = concat(["fun() -> ", no_final_dot(String), " end(). "]), + check1(F, FunString, Result), + CompileString = concat(["hd(lists:map(fun(_) -> ", no_final_dot(String), + " end, [foo])). "]), + check1(F, CompileString, Result). + +check1(F, String, Result) -> + Result = F(), + case catch parse_and_run(String) of + {value, Result, _} -> + ok; + Other -> + test_server:fail({eval, Other, Result}) + end. + +check(F, String, Result, BoundVars, LFH, EFH) -> + Result = F(), + case catch parse_and_run(String, LFH, EFH) of + {value, Result, Bs} -> + %% We just assume that Bs is an orddict... + Keys = orddict:fetch_keys(Bs), + case sort(BoundVars) == Keys of + true -> + ok; + false -> + test_server:fail({check, BoundVars, Keys}) + end, + ok; + Other -> + test_server:fail({check, Other, Result}) + end. + +error_check(String, Result) -> + case catch parse_and_run(String) of + {'EXIT', {Result,_}} -> + ok; + Other -> + test_server:fail({eval, Other, Result}) + end. + +error_check(String, Result, LFH, EFH) -> + case catch parse_and_run(String, LFH, EFH) of + {'EXIT', {Result,_}} -> + ok; + Other -> + test_server:fail({eval, Other, Result}) + end. + +eval_string(String) -> + {value, Result, _} = parse_and_run(String), + Result. + +parse_and_run(String) -> + {ok,Tokens,_} = erl_scan:string(String), + {ok, [Expr]} = erl_parse:parse_exprs(Tokens), + erl_eval:expr(Expr, []). + +parse_and_run(String, LFH, EFH) -> + {ok,Tokens,_} = erl_scan:string(String), + {ok, [Expr]} = erl_parse:parse_exprs(Tokens), + erl_eval:expr(Expr, [], LFH, EFH). + +no_final_dot(S) -> + case lists:reverse(S) of + " ." ++ R -> lists:reverse(R); + "." ++ R -> lists:reverse(R); + _ -> S + end. diff --git a/lib/debugger/test/exception_SUITE.erl b/lib/debugger/test/exception_SUITE.erl new file mode 100644 index 0000000000..a74a93fd22 --- /dev/null +++ b/lib/debugger/test/exception_SUITE.erl @@ -0,0 +1,256 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(exception_SUITE). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + badmatch/1,pending_errors/1,nil_arith/1]). + +-export([bad_guy/2]). + +-include("test_server.hrl"). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [badmatch, pending_errors, nil_arith]. + +-define(try_match(E), + catch ?MODULE:bar(), + {'EXIT', {{badmatch, nomatch}, _}} = (catch E = nomatch)). + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +badmatch(doc) -> "Test that deliberately bad matches are reported correctly."; +badmatch(suite) -> []; +badmatch(Config) when list(Config) -> + ?line ?try_match(a), + ?line ?try_match(42), + ?line ?try_match({a, b, c}), + ?line ?try_match([]), + ?line ?try_match(1.0), + ok. + +pending_errors(doc) -> + ["Test various exceptions, in the presence of a previous error suppressed ", + "in a guard."]; +pending_errors(suite) -> []; +pending_errors(Config) when list(Config) -> + ?line pending(e_badmatch, {badmatch, b}), + ?line pending(x, function_clause), + ?line pending(e_case, {case_clause, xxx}), + ?line pending(e_if, if_clause), + ?line pending(e_badarith, badarith), + ?line pending(e_undef, undef), + ?line pending(e_timeoutval, timeout_value), + ?line pending(e_badarg, badarg), + ?line pending(e_badarg_spawn, badarg), + ok. + +bad_guy(pe_badarith, Other) when Other+1 == 0 -> % badarith (suppressed) + ok; +bad_guy(pe_badarg, Other) when length(Other) > 0 -> % badarg (suppressed) + ok; +bad_guy(_, e_case) -> + case xxx of + ok -> ok + end; % case_clause +bad_guy(_, e_if) -> + if + a == b -> ok + end; % if_clause +bad_guy(_, e_badarith) -> + 1+b; % badarith +bad_guy(_, e_undef) -> + non_existing_module:foo(); % undef +bad_guy(_, e_timeoutval) -> + receive + after arne -> % timeout_value + ok + end; +bad_guy(_, e_badarg) -> + node(xxx); % badarg +bad_guy(_, e_badarg_spawn) -> + spawn({}, {}, {}); % badarg +bad_guy(_, e_badmatch) -> + a = b. % badmatch + +pending(Arg, Expected) -> + pending(pe_badarith, Arg, Expected), + pending(pe_badarg, Arg, Expected). + +pending(First, Second, Expected) -> + pending_catched(First, Second, Expected), + pending_exit_message([First, Second], Expected). + +pending_catched(First, Second, Expected) -> + ok = io:format("Catching bad_guy(~p, ~p)", [First, Second]), + case catch bad_guy(First, Second) of + {'EXIT', Reason} -> + pending(Reason, bad_guy, [First, Second], Expected); + Other -> + test_server:fail({not_exit, Other}) + end. + +pending_exit_message(Args, Expected) -> + ok = io:format("Trapping EXITs from spawn_link(~p, ~p, ~p)", + [?MODULE, bad_guy, Args]), + process_flag(trap_exit, true), + Pid = spawn_link(?MODULE, bad_guy, Args), + receive + {'EXIT', Pid, Reason} -> + pending(Reason, bad_guy, Args, Expected); + Other -> + test_server:fail({unexpected_message, Other}) + after 10000 -> + test_server:fail(timeout) + end, + process_flag(trap_exit, false). + +pending({badarg,[{erlang,Bif,BifArgs},{?MODULE,Func,Arity}|_]}, Func, Args, _Code) + when atom(Bif), list(BifArgs), length(Args) == Arity -> %Threaded code. + ok; +pending({badarg,[{erlang,Bif,BifArgs},{?MODULE,Func,Args}|_]}, Func, Args, _Code) + when atom(Bif), list(BifArgs) -> %From interpreted code. + ok; +pending({undef,[{non_existing_module,foo,[]}|_]}, _, _, _) -> + ok; +pending({function_clause,[{?MODULE,Func,Args}|_]}, Func, Args, _Code) -> + ok; +pending({Code,[{?MODULE,Func,Arity}|_]}, Func, Args, Code) when length(Args) == Arity -> %Threaded code + ok; +pending({Code,[{?MODULE,Func,Args}|_]}, Func, Args, Code) -> %From interpreted code. + ok; +pending(Reason, Func, Args, Code) -> + test_server:fail({bad_exit_reason,Reason,{Func,Args,Code}}). + +nil_arith(doc) -> + "Test that doing arithmetics on [] gives a badarith EXIT and not a crash."; +nil_arith(suite) -> + []; +nil_arith(Config) when list(Config) -> + ?line ba_plus_minus_times([], []), + + ?line ba_plus_minus_times([], 0), + ?line ba_plus_minus_times([], 42), + ?line ba_plus_minus_times([], 38724978123478923784), + ?line ba_plus_minus_times([], 38.72), + + ?line ba_plus_minus_times(0, []), + ?line ba_plus_minus_times(334, []), + ?line ba_plus_minus_times(387249797813478923784, []), + ?line ba_plus_minus_times(344.22, []), + + ?line ba_div_rem([], []), + + ?line ba_div_rem([], 0), + ?line ba_div_rem([], 1), + ?line ba_div_rem([], 42), + ?line ba_div_rem([], 38724978123478923784), + ?line ba_div_rem(344.22, []), + + ?line ba_div_rem(0, []), + ?line ba_div_rem(1, []), + ?line ba_div_rem(334, []), + ?line ba_div_rem(387249797813478923784, []), + ?line ba_div_rem(344.22, []), + + ?line ba_div_rem(344.22, 0.0), + ?line ba_div_rem(1, 0.0), + ?line ba_div_rem(392873498733971, 0.0), + + ?line ba_bop([], []), + ?line ba_bop(0, []), + ?line ba_bop(42, []), + ?line ba_bop(-42342742987343, []), + ?line ba_bop(238.342, []), + ?line ba_bop([], 0), + ?line ba_bop([], -243), + ?line ba_bop([], 243), + ?line ba_bop([], 2438724982478933), + ?line ba_bop([], 3987.37), + + ?line ba_bnot([]), + ?line ba_bnot(23.33), + + ?line ba_shift([], []), + ?line ba_shift([], 0), + ?line ba_shift([], 4), + ?line ba_shift([], -4), + ?line ba_shift([], 2343333333333), + ?line ba_shift([], -333333333), + ?line ba_shift([], 234.00), + ?line ba_shift(23, []), + ?line ba_shift(0, []), + ?line ba_shift(-3433443433433323, []), + ?line ba_shift(433443433433323, []), + ?line ba_shift(343.93, []), + ok. + +ba_plus_minus_times(A, B) -> + io:format("~p + ~p", [A, B]), + {'EXIT', {badarith, _}} = (catch A + B), + io:format("~p - ~p", [A, B]), + {'EXIT', {badarith, _}} = (catch A - B), + io:format("~p * ~p", [A, B]), + {'EXIT', {badarith, _}} = (catch A * B). + +ba_div_rem(A, B) -> + io:format("~p / ~p", [A, B]), + {'EXIT', {badarith, _}} = (catch A / B), + io:format("~p div ~p", [A, B]), + {'EXIT', {badarith, _}} = (catch A div B), + io:format("~p rem ~p", [A, B]), + {'EXIT', {badarith, _}} = (catch A rem B). + +ba_bop(A, B) -> + io:format("~p band ~p", [A, B]), + {'EXIT', {badarith, _}} = (catch A band B), + io:format("~p bor ~p", [A, B]), + {'EXIT', {badarith, _}} = (catch A bor B), + io:format("~p bxor ~p", [A, B]), + {'EXIT', {badarith, _}} = (catch A bxor B). + +ba_shift(A, B) -> + io:format("~p bsl ~p", [A, B]), + {'EXIT', {badarith, _}} = (catch A bsl B), + io:format("~p bsr ~p", [A, B]), + {'EXIT', {badarith, _}} = (catch A bsr B). + +ba_bnot(A) -> + io:format("bnot ~p", [A]), + {'EXIT', {badarith, _}} = (catch bnot A). diff --git a/lib/debugger/test/fun_SUITE.erl b/lib/debugger/test/fun_SUITE.erl new file mode 100644 index 0000000000..721048b6b6 --- /dev/null +++ b/lib/debugger/test/fun_SUITE.erl @@ -0,0 +1,233 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(fun_SUITE). + +-export([all/1, + init_per_testcase/2,end_per_testcase/2, + init_all/1,finish_all/1, + good_call/1,bad_apply/1,bad_fun_call/1,badarity/1, + ext_badarity/1,otp_6061/1]). +-export([nothing/0]). + +-include("test_server.hrl"). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [good_call,bad_apply,bad_fun_call,badarity,ext_badarity,otp_6061]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +end_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +good_call(Config) when is_list(Config) -> + ?line F = fun() -> ok end, + ?line ok = F(), + ?line FF = fun ?MODULE:nothing/0, + ?line ok = FF(), + ok. + +bad_apply(doc) -> + "Test that the correct EXIT code is returned for all types of bad funs."; +bad_apply(suite) -> []; +bad_apply(Config) when is_list(Config) -> + ?line bad_apply_fc(42, [0]), + ?line bad_apply_fc(xx, [1]), + ?line bad_apply_fc({}, [2]), + ?line bad_apply_fc({1}, [3]), + ?line bad_apply_fc({1,2,3}, [4]), + ?line bad_apply_fc({1,2,3}, [5]), + ?line bad_apply_fc({1,2,3,4}, [6]), + ?line bad_apply_fc({1,2,3,4,5,6}, [7]), + ?line bad_apply_fc({1,2,3,4,5}, [8]), + ?line bad_apply_badarg({1,2}, [9]), + ok. + +bad_apply_fc(Fun, Args) -> + Res = (catch apply(Fun, Args)), + erlang:garbage_collect(), + erlang:yield(), + case Res of + {'EXIT',{{badfun,Fun},_Where}} -> + ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res]); + Other -> + ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res]), + ?t:fail({bad_result,Other}) + end. + +bad_apply_badarg(Fun, Args) -> + Res = (catch apply(Fun, Args)), + erlang:garbage_collect(), + erlang:yield(), + case Res of + {'EXIT',{{badfun,Fun},_Where}} -> + ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res]); + Other -> + ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res]), + ?t:fail({bad_result, Other}) + end. + +bad_fun_call(doc) -> + "Try directly calling bad funs."; +bad_fun_call(suite) -> []; +bad_fun_call(Config) when is_list(Config) -> + ?line bad_call_fc(42), + ?line bad_call_fc(xx), + ?line bad_call_fc({}), + ?line bad_call_fc({1}), + ?line bad_call_fc({1,2,3}), + ?line bad_call_fc({1,2,3}), + ?line bad_call_fc({1,2,3,4}), + ?line bad_call_fc({1,2,3,4,5,6}), + ?line bad_call_fc({1,2,3,4,5}), + ?line bad_call_fc({1,2}), + ok. + +bad_call_fc(Fun) -> + Args = [some,stupid,args], + Res = (catch Fun(Args)), + case Res of + {'EXIT',{{badfun,Fun},_Where}} -> + ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]); + Other -> + ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]), + ?t:fail({bad_result,Other}) + end. + +%% Call and apply valid external funs with wrong number of arguments. + +badarity(Config) when is_list(Config) -> + ?line Fun = fun() -> ok end, + ?line Stupid = {stupid,arguments}, + ?line Args = [some,{stupid,arguments},here], + + %% Simple call. + + ?line Res = (catch Fun(some, Stupid, here)), + erlang:garbage_collect(), + erlang:yield(), + case Res of + {'EXIT',{{badarity,{Fun,Args}},[_|_]}} -> + ?line ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]); + _ -> + ?line ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]), + ?line ?t:fail({bad_result,Res}) + end, + + %% Apply. + + ?line Res2 = (catch apply(Fun, Args)), + erlang:garbage_collect(), + erlang:yield(), + case Res2 of + {'EXIT',{{badarity,{Fun,Args}},[_|_]}} -> + ?line ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res2]); + _ -> + ?line ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res2]), + ?line ?t:fail({bad_result,Res2}) + end, + ok. + +%% Call and apply valid external funs with wrong number of arguments. + +ext_badarity(Config) when is_list(Config) -> + ?line Fun = fun ?MODULE:nothing/0, + ?line Stupid = {stupid,arguments}, + ?line Args = [some,{stupid,arguments},here], + + %% Simple call. + + ?line Res = (catch Fun(some, Stupid, here)), + erlang:garbage_collect(), + erlang:yield(), + case Res of + {'EXIT',{{badarity,{Fun,Args}},_}} -> + ?line ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]); + _ -> + ?line ok = io:format("~p(~p) -> ~p\n", [Fun,Args,Res]), + ?line ?t:fail({bad_result,Res}) + end, + + %% Apply. + + ?line Res2 = (catch apply(Fun, Args)), + erlang:garbage_collect(), + erlang:yield(), + case Res2 of + {'EXIT',{{badarity,{Fun,Args}},_}} -> + ?line ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res2]); + _ -> + ?line ok = io:format("apply(~p, ~p) -> ~p\n", [Fun,Args,Res2]), + ?line ?t:fail({bad_result,Res2}) + end, + ok. + +nothing() -> + ok. + +otp_6061(suite) -> + []; +otp_6061(doc) -> + ["Test handling of fun expression referring to uninterpreted code"]; +otp_6061(Config) when is_list(Config) -> + + ?line OrigFlag = process_flag(trap_exit, true), + + ?line Self = self(), + ?line Pid = spawn_link(fun() -> test_otp_6061(Self) end), + + receive + working -> + ?line ok; + not_working -> + ?line ?t:fail(not_working); + {'EXIT', Pid, Reason} -> + ?line ?t:fail({crash, Reason}) + after + 5000 -> + ?line ?t:fail(timeout) + end, + + ?line process_flag(trap_exit, OrigFlag), + + ok. + +test_otp_6061(Starter) -> + Passes = [2], + PassesF = [fun() -> Starter ! not_working end, + fun() -> Starter ! working end, + fun() -> Starter ! not_working end], + lists:foreach(fun(P)->(lists:nth(P,PassesF))() end,Passes). diff --git a/lib/debugger/test/guard_SUITE.erl b/lib/debugger/test/guard_SUITE.erl new file mode 100644 index 0000000000..b5269989c8 --- /dev/null +++ b/lib/debugger/test/guard_SUITE.erl @@ -0,0 +1,1479 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(guard_SUITE). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + bad_arith/1,bad_tuple/1,test_heap_guards/1,guard_bifs/1, + type_tests/1,const_guard/1, + const_cond/1,basic_not/1,complex_not/1, + semicolon/1,complex_semicolon/1,comma/1, + or_guard/1,more_or_guards/1, + complex_or_guards/1,and_guard/1, + xor_guard/1,more_xor_guards/1, + old_guard_tests/1, + build_in_guard/1,gbif/1, + t_is_boolean/1,is_function_2/1, + tricky/1,rel_ops/1, + basic_andalso_orelse/1,traverse_dcd/1, + check_qlc_hrl/1]). + +-include("test_server.hrl"). + +-export([init/4]). +-import(lists, [member/2]). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [bad_arith,bad_tuple,test_heap_guards,guard_bifs,type_tests,const_guard, + const_cond,basic_not,complex_not, + semicolon,complex_semicolon, + comma,or_guard,more_or_guards, + complex_or_guards,and_guard, + xor_guard,more_xor_guards, + build_in_guard,old_guard_tests,gbif, + t_is_boolean,is_function_2,tricky,rel_ops, + basic_andalso_orelse,traverse_dcd,check_qlc_hrl]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + ?line Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +bad_arith(doc) -> "Test that a bad arithmetic operation in a guard works correctly."; +bad_arith(suite) -> []; +bad_arith(Config) when list(Config) -> + ?line 5 = bad_arith1(2, 3), + ?line 10 = bad_arith1(1, infinity), + ?line 10 = bad_arith1(infinity, 1), + ?line 42 = bad_div(24, 0), + ok. + +bad_arith1(T1, T2) when T1+T2 < 10 -> + T1+T2; +bad_arith1(_, _) -> + 10. + +bad_div(A, B) when A/B > 0 -> + A/B; +bad_div(A, B) when A div B > 0 -> + A div B; +bad_div(_A, _B) -> + 42. + +bad_tuple(doc) -> "Test that bad arguments to element/2 are handled correctly."; +bad_tuple(suite) -> []; +bad_tuple(Config) when list(Config) -> + ?line error = bad_tuple1(a), + ?line error = bad_tuple1({a, b}), + ?line x = bad_tuple1({x, b}), + ?line y = bad_tuple1({a, b, y}), + ok. + +bad_tuple1(T) when element(1, T) == x -> x; +bad_tuple1(T) when element(3, T) == y -> y; +bad_tuple1(_) -> error. + +test_heap_guards(doc) -> ""; +test_heap_guards(suite) -> []; +test_heap_guards(Config) when list(Config) -> + ?line process_flag(trap_exit, true), + ?line Tuple = {a, tuple, is, built, here, xxx}, + ?line List = [a, list, is, built, here], + + ?line try_fun(fun a_case/1, [Tuple], [Tuple]), + ?line try_fun(fun a_case/1, [List], [List, List]), + ?line try_fun(fun a_case/1, [a], [a]), + + ?line try_fun(fun an_if/1, [Tuple], [Tuple]), + ?line try_fun(fun an_if/1, [List], [List, List]), + ?line try_fun(fun an_if/1, [a], [a]), + + ?line try_fun(fun receive_test/1, [Tuple], [Tuple]), + ?line try_fun(fun receive_test/1, [List], [List, List]), + ?line try_fun(fun receive_test/1, [a], [a]), + ok. + +a_case(V) -> + case V of + T when T == {a, tuple, is, built, here, xxx} -> + [T]; + L when L == [a, list, is, built, here] -> + [L, L]; + a -> + [a] + end. + +an_if(V) -> + if + V == {a, tuple, is, built, here, xxx} -> + [V]; + V == [a, list, is, built, here] -> + [V, V]; + V == a -> + [a] + end. + +receive_test(V) -> + self() ! V, + a_receive(). + +a_receive() -> + receive + T when T == {a, tuple, is, built, here, xxx} -> + [T]; + L when L == [a, list, is, built, here] -> + [L, L]; + a -> + [a] + end. + +try_fun(Fun, Args, Result) -> + try_fun(16, Fun, Args, Result, []). + +try_fun(0, _, _, _, _) -> + ok; +try_fun(Iter, Fun, Args, Result, Filler) -> + Pid = spawn_link(?MODULE, init, [self(),Fun,Args,list_to_tuple(Filler)]), + receive + {'EXIT',Pid,{result,Result}} -> + ?line try_fun(Iter-1, Fun, Args, Result, [0|Filler]); + {'EXIT',Pid,{result,Other}} -> + ?line io:format("Expected ~p; got ~p~n", [Result,Other]), + ?line test_server:fail(); + Other -> + ?line test_server:fail({unexpected_message,Other}) + end. + +init(_ReplyTo, Fun, Args, Filler) -> + Result = {result, apply(Fun, Args)}, + dummy(Filler), + io:format("~p: result = ~p\n", [?LINE,Result]), + exit(Result). + +dummy(_) -> + ok. + +guard_bifs(doc) -> "Test all guard bifs with nasty (but legal arguments)."; +guard_bifs(suite) -> []; +guard_bifs(Config) when list(Config) -> + ?line Big = -237849247829874297658726487367328971246284736473821617265433, + ?line Float = 387924.874, + + %% Succeding use of guard bifs. + + ?line try_gbif('abs/1', Big, -Big), + ?line try_gbif('float/1', Big, float(Big)), + ?line try_gbif('trunc/1', Float, 387924.0), + ?line try_gbif('round/1', Float, 387925.0), + ?line try_gbif('length/1', [], 0), + + ?line try_gbif('length/1', [a], 1), + ?line try_gbif('length/1', [a, b], 2), + ?line try_gbif('length/1', lists:seq(0, 31), 32), + + ?line try_gbif('hd/1', [a], a), + ?line try_gbif('hd/1', [a, b], a), + + ?line try_gbif('tl/1', [a], []), + ?line try_gbif('tl/1', [a, b], [b]), + ?line try_gbif('tl/1', [a, b, c], [b, c]), + + ?line try_gbif('size/1', {}, 0), + ?line try_gbif('size/1', {a}, 1), + ?line try_gbif('size/1', {a, b}, 2), + ?line try_gbif('size/1', {a, b, c}, 3), + ?line try_gbif('size/1', list_to_binary([]), 0), + ?line try_gbif('size/1', list_to_binary([1]), 1), + ?line try_gbif('size/1', list_to_binary([1, 2]), 2), + ?line try_gbif('size/1', list_to_binary([1, 2, 3]), 3), + + ?line try_gbif('element/2', {x}, {1, x}), + ?line try_gbif('element/2', {x, y}, {1, x}), + ?line try_gbif('element/2', {x, y}, {2, y}), + + ?line try_gbif('self/0', 0, self()), + ?line try_gbif('node/0', 0, node()), + ?line try_gbif('node/1', self(), node()), + + %% Failing use of guard bifs. + + ?line try_fail_gbif('abs/1', Big, 1), + ?line try_fail_gbif('abs/1', [], 1), + + ?line try_fail_gbif('float/1', Big, 42), + ?line try_fail_gbif('float/1', [], 42), + + ?line try_fail_gbif('trunc/1', Float, 0.0), + ?line try_fail_gbif('trunc/1', [], 0.0), + + ?line try_fail_gbif('round/1', Float, 1.0), + ?line try_fail_gbif('round/1', [], a), + + ?line try_fail_gbif('length/1', [], 1), + ?line try_fail_gbif('length/1', [a], 0), + ?line try_fail_gbif('length/1', a, 0), + ?line try_fail_gbif('length/1', {a}, 0), + + ?line try_fail_gbif('hd/1', [], 0), + ?line try_fail_gbif('hd/1', [a], x), + ?line try_fail_gbif('hd/1', x, x), + + ?line try_fail_gbif('tl/1', [], 0), + ?line try_fail_gbif('tl/1', [a], x), + ?line try_fail_gbif('tl/1', x, x), + + ?line try_fail_gbif('size/1', {}, 1), + ?line try_fail_gbif('size/1', [], 0), + ?line try_fail_gbif('size/1', [a], 1), + + ?line try_fail_gbif('element/2', {}, {1, x}), + ?line try_fail_gbif('element/2', {x}, {1, y}), + ?line try_fail_gbif('element/2', [], {1, z}), + + ?line try_fail_gbif('self/0', 0, list_to_pid("<0.0.0>")), + ?line try_fail_gbif('node/0', 0, xxxx), + ?line try_fail_gbif('node/1', self(), xxx), + ?line try_fail_gbif('node/1', yyy, xxx), + ok. + +try_gbif(Id, X, Y) -> + case guard_bif(Id, X, Y) of + {Id, X, Y} -> + io:format("guard_bif(~p, ~p, ~p) -- ok", [Id, X, Y]); + Other -> + ?line ok = io:format("guard_bif(~p, ~p, ~p) -- bad result: ~p\n", + [Id, X, Y, Other]), + ?line test_server:fail() + end. + +try_fail_gbif(Id, X, Y) -> + case catch guard_bif(Id, X, Y) of + {'EXIT', {function_clause,{?MODULE,guard_bif,[Id,X,Y]}}} -> %Jam + io:format("guard_bif(~p, ~p, ~p) -- ok", [Id,X,Y]); + {'EXIT', {function_clause,[{?MODULE,guard_bif,[Id,X,Y]}|_]}} -> %Beam + io:format("guard_bif(~p, ~p, ~p) -- ok", [Id,X,Y]); + Other -> + ?line ok = io:format("guard_bif(~p, ~p, ~p) -- bad result: ~p\n", + [Id, X, Y, Other]), + ?line test_server:fail() + end. + +guard_bif('abs/1', X, Y) when abs(X) == Y -> + {'abs/1', X, Y}; +guard_bif('float/1', X, Y) when float(X) == Y -> + {'float/1', X, Y}; +guard_bif('trunc/1', X, Y) when trunc(X) == Y -> + {'trunc/1', X, Y}; +guard_bif('round/1', X, Y) when round(X) == Y -> + {'round/1', X, Y}; +guard_bif('length/1', X, Y) when length(X) == Y -> + {'length/1', X, Y}; +guard_bif('hd/1', X, Y) when hd(X) == Y -> + {'hd/1', X, Y}; +guard_bif('tl/1', X, Y) when tl(X) == Y -> + {'tl/1', X, Y}; +guard_bif('size/1', X, Y) when size(X) == Y -> + {'size/1', X, Y}; +guard_bif('element/2', X, {Pos, Expected}) when element(Pos, X) == Expected -> + {'element/2', X, {Pos, Expected}}; +guard_bif('self/0', X, Y) when self() == Y -> + {'self/0', X, Y}; +guard_bif('node/0', X, Y) when node() == Y -> + {'node/0', X, Y}; +guard_bif('node/1', X, Y) when node(X) == Y -> + {'node/1', X, Y}. + +type_tests(doc) -> "Test the type tests."; +type_tests(suite) -> []; +type_tests(Config) when list(Config) -> + ?line Types = all_types(), + ?line Tests = type_test_desc(), + ?line put(errors, 0), + ?line put(violations, 0), + ?line type_tests(Tests, Types), + ?line case {get(errors), get(violations)} of + {0, 0} -> + ok; + {0, N} -> + {comment, integer_to_list(N) ++ " standard violation(s)"}; + {Errors, Violations} -> + io:format("~p sub test(s) failed, ~p violation(s)", + [Errors, Violations]), + ?line test_server:fail() + end. + +type_tests([{Test, AllowedTypes}| T], AllTypes) -> + type_tests(Test, AllTypes, AllowedTypes), + type_tests(T, AllTypes); +type_tests([], _) -> + ok. + +type_tests(Test, [Type|T], Allowed) -> + {TypeTag, Value} = Type, + case member(TypeTag, Allowed) of + true -> + case catch type_test(Test, Value) of + Test -> + ok; + _Other -> + io:format("Test ~p(~p) failed", [Test, Value]), + put(errors, get(errors) + 1) + end; + false -> + case catch type_test(Test, Value) of + {'EXIT', {function_clause, {?MODULE, type_test, [Test, Value]}}} -> + ok; + {'EXIT', {function_clause,[{?MODULE,type_test,[Test,Value]}|_]}} -> + ok; + {'EXIT',Other} -> + ?line test_server:fail({unexpected_error_reason,Other}); + tuple when function(Value) -> + io:format("Standard violation: Test ~p(~p) should fail", + [Test, Value]), + put(violations, get(violations) + 1); + _Other -> + io:format("Test ~p(~p) succeeded (should fail)", [Test, Value]), + put(errors, get(errors) + 1) + end + end, + type_tests(Test, T, Allowed); +type_tests(_, [], _) -> + ok. + +all_types() -> + [{small, 42}, + {big, 392742928742947293873938792874019287447829874290742}, + {float, 3.14156}, + {nil, []}, + {cons, [a]}, + {tuple, {a, b}}, + {atom, xxxx}, + {ref, make_ref()}, + {pid, self()}, + {port, open_port({spawn, efile}, [])}, + {function, fun(X) -> X+1, "" end}, + {binary, list_to_binary([])}]. + +type_test_desc() -> + [{integer, [small, big]}, + {float, [float]}, + {number, [small, big, float]}, + {atom, [atom]}, + {list, [cons, nil]}, + {nonempty_list, [cons]}, + {nil, [nil]}, + {tuple, [tuple]}, + {pid, [pid]}, + {port, [port]}, + {reference, [ref]}, + {function, [function]}]. + +type_test(integer, X) when integer(X) -> + integer; +type_test(float, X) when float(X) -> + float; +type_test(number, X) when number(X) -> + number; +type_test(atom, X) when atom(X) -> + atom; +type_test(list, X) when list(X) -> + list; +type_test(nonempty_list, [_]) -> + nonempty_list; +type_test(nil, []) -> + nil; +type_test(tuple, X) when tuple(X) -> + tuple; +type_test(pid, X) when pid(X) -> + pid; +type_test(reference, X) when reference(X) -> + reference; +type_test(port, X) when port(X) -> + port; +type_test(binary, X) when binary(X) -> + binary; +type_test(function, X) when function(X) -> + function. + +const_guard(Config) when is_list(Config) -> + ?line if + (0 == 0) and ((0 == 0) or (0 == 0)) -> + ok + end. + + +const_cond(Config) when is_list(Config) -> + ?line ok = const_cond({}, 0), + ?line ok = const_cond({a}, 1), + ?line error = const_cond({a,b}, 3), + ?line error = const_cond({a}, 0), + ?line error = const_cond({a,b}, 1), + ok. + +const_cond(T, Sz) -> + case T of + _X when false -> never; + _X when tuple(T), eq == eq, size(T) == Sz -> ok; + _X when tuple(T), eq == leq, size(T) =< Sz -> ok; + _X -> error + end. + +basic_not(Config) when is_list(Config) -> + True = id(true), + False = id(false), + Glurf = id(glurf), + A = id(5), + B = id(37.5), + C = id(-1), + D = id(5), + ATuple = {False,True,Glurf}, + + ?line check(fun() -> if not false -> ok; true -> error end end, ok), + ?line check(fun() -> if not true -> ok; true -> error end end, error), + ?line check(fun() -> if not False -> ok; true -> error end end, ok), + ?line check(fun() -> if not True -> ok; true -> error end end, error), + + ?line check(fun() -> if A > B -> gt; A < B -> lt; A == B -> eq end end, lt), + ?line check(fun() -> if A > C -> gt; A < C -> lt; A == C -> eq end end, gt), + ?line check(fun() -> if A > D -> gt; A < D -> lt; A == D -> eq end end, eq), + + ?line check(fun() -> if not (7 > 453) -> le; not (7 < 453) -> ge; + not (7 == 453) -> ne; true -> eq end end, le), + ?line check(fun() -> if not (7 > -8) -> le; not (7 < -8) -> ge; + not (7 == -8) -> ne; true -> eq end end, ge), + ?line check(fun() -> if not (7 > 7) -> le; not (7 < 7) -> ge; + not (7 == 7) -> ne; true -> eq end end, le), + + ?line check(fun() -> if not (A > B) -> le; not (A < B) -> ge; + not (A == B) -> ne; true -> eq end end, le), + ?line check(fun() -> if not (A > C) -> le; not (A < C) -> ge; + not (A == C) -> ne; true -> eq end end, ge), + ?line check(fun() -> if not (A > D) -> le; not (A < D) -> ge; + not (A == D) -> ne; true -> eq end end, le), + + ?line check(fun() -> if not element(1, ATuple) -> ok; true -> error end end, ok), + ?line check(fun() -> if not element(2, ATuple) -> ok; true -> error end end, error), + ?line check(fun() -> if not element(3, ATuple) -> ok; true -> error end end, error), + + ?line check(fun() -> if not glurf -> ok; true -> error end end, error), + ?line check(fun() -> if not Glurf -> ok; true -> error end end, error), + + ok. + +complex_not(Config) when is_list(Config) -> + ATuple = id({false,true,gurka}), + ?line check(fun() -> if not(element(1, ATuple)) -> ok; true -> error end end, ok), + ?line check(fun() -> if not(element(2, ATuple)) -> ok; true -> error end end, error), + + ?line check(fun() -> if not(element(3, ATuple) == gurka) -> ok; + true -> error end end, error), + ?line check(fun() -> if not(element(3, ATuple) =/= gurka) -> ok; + true -> error end end, ok), + + ?line check(fun() -> if {a,not(element(2, ATuple))} == {a,false} -> ok; + true -> error end end, ok), + ?line check(fun() -> if {a,not(element(1, ATuple))} == {a,false} -> ok; + true -> error end end, error), + + ?line check(fun() -> if not(element(1, ATuple) or element(3, ATuple)) -> ok; + true -> error end end, error), + + %% orelse + ?line check(fun() -> if not(element(1, ATuple) orelse element(3, ATuple)) -> ok; + true -> error end end, error), + + ok. + +semicolon(Config) when is_list(Config) -> + + %% True/false combined using ';' (literal atoms). + + ?line check(fun() -> if true; false -> ok end end, ok), + ?line check(fun() -> if false; true -> ok end end, ok), + ?line check(fun() -> if true; true -> ok end end, ok), + ?line check(fun() -> if false; false -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if false; false -> ok end), + exit + end, exit), + + %% True/false combined used ';'. + + True = id(true), + False = id(false), + + ?line check(fun() -> if True; False -> ok end end, ok), + ?line check(fun() -> if False; True -> ok end end, ok), + ?line check(fun() -> if True; True -> ok end end, ok), + ?line check(fun() -> if False; False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if False; False -> ok end), + exit + end, exit), + + %% Combine true/false with a non-boolean value. + Glurf = id(glurf), + + + ?line check(fun() -> if True; Glurf -> ok end end, ok), + ?line check(fun() -> if Glurf; True -> ok end end, ok), + ?line check(fun() -> if Glurf; Glurf -> ok; true -> error end end, error), + ?line check(fun() -> if False; Glurf -> ok; true -> error end end, error), + ?line check(fun() -> if Glurf; False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if Glurf; Glurf -> ok end), + exit + end, exit), + + %% Combine true/false with errors. + + ATuple = id({false,true,gurka}), + + ?line check(fun() -> if True; element(42, ATuple) -> ok end end, ok), + ?line check(fun() -> if element(42, ATuple); True -> ok end end, ok), + ?line check(fun() -> if element(42, ATuple); element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> if False; element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> if element(42, ATuple); + False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if element(42, ATuple); + element(42, ATuple) -> ok end), + exit + end, exit), + + ok. + +complex_semicolon(Config) when is_list(Config) -> + ?line ok = csemi1(int, {blurf}), + ?line ok = csemi1(string, {blurf}), + ?line ok = csemi1(float, [a]), + ?line error = csemi1(35, 42), + + %% 2 + ?line ok = csemi2({}, {a,b,c}), + ?line ok = csemi2({1,3.5}, {a,b,c}), + ?line ok = csemi2(dum, {a,b,c}), + + ?line ok = csemi2({45,-19.3}, {}), + ?line ok = csemi2({45,-19.3}, {dum}), + ?line ok = csemi2({45,-19.3}, {dum,dum}), + + ?line error = csemi2({45}, {dum}), + ?line error = csemi2([], {dum}), + ?line error = csemi2({dum}, []), + ?line error = csemi2([], []), + + %% 3 + ?line csemi3(fun csemi3a/4), + ?line csemi3(fun csemi3b/4), + ?line csemi3(fun csemi3c/4), + + %% 4 + ?line csemi4(fun csemi4a/4), + ?line csemi4(fun csemi4b/4), + ?line csemi4(fun csemi4c/4), + ?line csemi4(fun csemi4d/4), + + %% 4, 'orelse' instead of 'or' + ?line csemi4_orelse(fun csemi4_orelse_a/4), + ?line csemi4_orelse(fun csemi4_orelse_b/4), + ?line csemi4_orelse(fun csemi4_orelse_c/4), + ?line csemi4_orelse(fun csemi4_orelse_d/4), + + ok. + +csemi1(Type, Val) when is_list(Val), Type == float; + Type == int; Type == string -> ok; +csemi1(_, _) -> error. + +csemi2(A, B) when size(A) > 1; size(B) > 2 -> ok; +csemi2(_, _) -> error. + +csemi3(Csemi3) -> + ok = Csemi3({}, {a,b,c}, [0], [0]), + ok = Csemi3({1,3.5}, {a,b,c}, -1, -1), + ok = Csemi3(dum, {a,b,c}, 0.0, 0.0), + ok = Csemi3(dum, {c}, b, a), + ok = Csemi3(dum, <<1,2,3>>, 0.0, 0.0), + ok = Csemi3(<<3.5/float>>, {a,b,c}, -1, -1), + + ok = Csemi3({45,-19.3}, {}, [], []), + ok = Csemi3({45,-19.3}, {dum}, 42, 42), + ok = Csemi3({45,-19.3}, {dum,dum}, 33, 33), + + ok = Csemi3({45}, {dum}, 1.0, 0), + ok = Csemi3([a], {dum}, 1.0, 0), + ok = Csemi3({dum}, [], 1.0, 0), + ok = Csemi3([], [], 1.0, 0), + ok = Csemi3(blurf, {dum}, 1.0, 0), + ok = Csemi3({a}, blurf, 1.0, 0), + ok = Csemi3([a], [dum], 1.0, 0), + ok = Csemi3({dum}, [], 1.0, 0), + ok = Csemi3([], [], 1.0, 0), + + error = Csemi3({45}, {dum}, 0, 0), + error = Csemi3([a], {dum}, 0, 0), + error = Csemi3({dum}, [], 0, 0), + error = Csemi3([], [], 0, 0), + ok. + +csemi3a(A, B, X, Y) when X > Y; size(A) > 1; size(B) > 2 -> ok; +csemi3a(_, _, _, _) -> error. + +csemi3b(A, B, X, Y) when size(A) > 1; X > Y; size(B) > 2 -> ok; +csemi3b(_, _, _, _) -> error. + +csemi3c(A, B, X, Y) when size(A) > 1; size(B) > 2; X > Y -> ok; +csemi3c(_, _, _, _) -> error. + + +csemi4(Test) -> + ok = Test({a,b}, 2, {c,d}, 2), + ok = Test({1,2,3}, 0, [], 0), + ok = Test({}, 2, blurf, 0), + ok = Test({}, 2, {1}, 2), + + error = Test([], 4, {}, 0), + error = Test({}, 0, [a,b], 4), + error = Test({}, 0, [a,b], 0), + error = Test([], 0, {}, 0), + error = Test({}, 0, {}, 0), + + ok. + +csemi4a(A, X, B, Y) when (size(A) > 1) or (X > 1); + (size(B) > 1) or (Y > 1) -> ok; +csemi4a(_, _, _, _) -> error. + +csemi4b(A, X, B, Y) when (X > 1) or (size(A) > 1); + (size(B) > 1) or (Y > 1) -> ok; +csemi4b(_, _, _, _) -> error. + +csemi4c(A, X, B, Y) when (size(A) > 1) or (X > 1); + (Y > 1) or (size(B) > 1) -> ok; +csemi4c(_, _, _, _) -> error. + +csemi4d(A, X, B, Y) when (X > 1) or (size(A) > 1); + (Y > 1) or (size(B) > 1) -> ok; +csemi4d(_, _, _, _) -> error. + + +csemi4_orelse(Test) -> + ok = Test({a,b}, 2, {c,d}, 2), + ok = Test({1,2,3}, 0, [], 0), + ok = Test({}, 2, blurf, 0), + ok = Test({}, 2, {1}, 2), + + ?line error = Test([], 1, {}, 0), + + ok. + +csemi4_orelse_a(A, X, B, Y) when (size(A) > 1) orelse (X > 1); + (size(B) > 1) orelse (Y > 1) -> ok; +csemi4_orelse_a(_, _, _, _) -> error. + +csemi4_orelse_b(A, X, B, Y) when (X > 1) orelse (size(A) > 1); + (size(B) > 1) orelse (Y > 1) -> ok; +csemi4_orelse_b(_, _, _, _) -> error. + +csemi4_orelse_c(A, X, B, Y) when (size(A) > 1) orelse (X > 1); + (Y > 1) orelse (size(B) > 1) -> ok; +csemi4_orelse_c(_, _, _, _) -> error. + +csemi4_orelse_d(A, X, B, Y) when (X > 1) or (size(A) > 1); + (Y > 1) or (size(B) > 1) -> ok; +csemi4_orelse_d(_, _, _, _) -> error. + + +comma(Config) when is_list(Config) -> + + %% ',' combinations of literal true/false. + + ?line check(fun() -> if true, false -> ok; true -> error end end, error), + ?line check(fun() -> if false, true -> ok; true -> error end end, error), + ?line check(fun() -> if true, true -> ok end end, ok), + ?line check(fun() -> if false, false -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if true, false -> ok; + false, true -> ok; + false, false -> ok + end), + exit + end, exit), + + %% ',' combinations of true/false in variables. + + True = id(true), + False = id(false), + + ?line check(fun() -> if True, False -> ok; true -> error end end, error), + ?line check(fun() -> if False, True -> ok; true -> error end end, error), + ?line check(fun() -> if True, True -> ok end end, ok), + ?line check(fun() -> if False, False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True, False -> ok; + False, True -> ok; + False, False -> ok + end), + exit + end, exit), + + %% ',' combinations of true/false, and non-boolean in variables. + + Glurf = id(glurf), + + ?line check(fun() -> if True, Glurf -> ok; true -> error end end, error), + ?line check(fun() -> if Glurf, True -> ok; true -> error end end, error), + ?line check(fun() -> if True, True -> ok end end, ok), + ?line check(fun() -> if Glurf, Glurf -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True, Glurf -> ok; + Glurf, True -> ok; + Glurf, Glurf -> ok + end), + exit + end, exit), + + %% ',' combinations of true/false with errors. + ATuple = id({a,b,c}), + + ?line check(fun() -> if True, element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> if element(42, ATuple), True -> ok; + true -> error end end, error), + ?line check(fun() -> if True, True -> ok end end, ok), + ?line check(fun() -> if element(42, ATuple), element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True, element(42, ATuple) -> ok; + element(42, ATuple), True -> ok; + element(42, ATuple), element(42, ATuple) -> ok + end), + exit + end, exit), + + ok. + +or_guard(Config) when is_list(Config) -> + True = id(true), + False = id(false), + Glurf = id(glurf), + + %% 'or' combinations of literal true/false. + ?line check(fun() -> if true or false -> ok end end, ok), + ?line check(fun() -> if false or true -> ok end end, ok), + ?line check(fun() -> if true or true -> ok end end, ok), + ?line check(fun() -> if false or false -> ok; true -> error end end, error), + + ?line check(fun() -> if glurf or true -> ok; true -> error end end, error), + ?line check(fun() -> if true or glurf -> ok; true -> error end end, error), + ?line check(fun() -> if glurf or glurf -> ok; true -> error end end, error), + + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if false or false -> ok end), + exit + end, exit), + + + %% 'or' combinations using variables containing true/false. + ?line check(fun() -> if True or False -> ok end end, ok), + ?line check(fun() -> if False or True -> ok end end, ok), + ?line check(fun() -> if True or True -> ok end end, ok), + ?line check(fun() -> if False or False -> ok; true -> error end end, error), + + ?line check(fun() -> if True or Glurf -> ok; true -> error end end, error), + ?line check(fun() -> if Glurf or True -> ok; true -> error end end, error), + ?line check(fun() -> if Glurf or Glurf -> ok; true -> error end end, error), + + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if False or False -> ok end), + exit + end, exit), + + ok. + +more_or_guards(Config) when is_list(Config) -> + True = id(true), + False = id(false), + ATuple = id({false,true,gurka}), + + ?line check(fun() -> + if element(42, ATuple) or False -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if False or element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(18, ATuple) or element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if True or element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(42, ATuple) or True -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(1, ATuple) or element(42, ATuple) or True -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(1, ATuple) or True or element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if + (<<False:8>> == <<0>>) or element(2, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if + element(2, ATuple) or (<<True:8>> == <<1>>) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(2, ATuple) or element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if + element(1, ATuple) or + element(2, ATuple) or + element(19, ATuple) -> ok; + true -> error end + end, error), + ok. + +complex_or_guards(Config) when is_list(Config) -> + %% complex_or_1/2 + ?line ok = complex_or_1({a,b,c,d}, {1,2,3}), + ?line ok = complex_or_1({a,b,c,d}, {1}), + ?line ok = complex_or_1({a}, {1,2,3}), + ?line error = complex_or_1({a}, {1}), + + ?line error = complex_or_1(1, 2), + ?line error = complex_or_1([], {a,b,c,d}), + ?line error = complex_or_1({a,b,c,d}, []), + + + %% complex_or_2/1 + ?line ok = complex_or_2({true,{}}), + ?line ok = complex_or_2({false,{a}}), + ?line ok = complex_or_2({false,{a,b,c}}), + ?line ok = complex_or_2({true,{a,b,c,d}}), + + ?line error = complex_or_2({blurf,{a,b,c}}), + + ?line error = complex_or_2({true}), + ?line error = complex_or_2({true,no_tuple}), + ?line error = complex_or_2({true,[]}), + + %% complex_or_3/2 + ?line ok = complex_or_3({true}, {}), + ?line ok = complex_or_3({false}, {a}), + ?line ok = complex_or_3({false}, {a,b,c}), + ?line ok = complex_or_3({true}, {a,b,c,d}), + ?line ok = complex_or_3({false}, <<1,2,3>>), + ?line ok = complex_or_3({true}, <<1,2,3,4>>), + + ?line error = complex_or_3(blurf, {a,b,c}), + + ?line error = complex_or_3({false}, <<1,2,3,4>>), + ?line error = complex_or_3([], <<1,2>>), + ?line error = complex_or_3({true}, 45), + ?line error = complex_or_3(<<>>, <<>>), + + %% complex_or_4/2 + ?line ok = complex_or_4(<<1,2,3>>, {true}), + ?line ok = complex_or_4(<<1,2,3>>, {false}), + ?line ok = complex_or_4(<<1,2,3>>, {true}), + ?line ok = complex_or_4({1,2,3}, {true}), + ?line error = complex_or_4({1,2,3,4}, {false}), + + ?line error = complex_or_4(<<1,2,3,4>>, []), + ?line error = complex_or_4([], {true}), + + %% complex_or_5/2 + ?line ok = complex_or_5(<<1>>, {false}), + ?line ok = complex_or_5(<<1,2,3>>, {true}), + ?line ok = complex_or_5(<<1,2,3,4>>, {false}), + ?line ok = complex_or_5({1,2,3}, {false}), + ?line ok = complex_or_5({1,2,3,4}, {false}), + + ?line error = complex_or_5(blurf, {false}), + ?line error = complex_or_5(<<1>>, klarf), + ?line error = complex_or_5(blurf, klarf), + + %% complex_or_6/2 + ?line ok = complex_or_6({true,true}, {1,2,3,4}), + ?line ok = complex_or_6({true,true}, <<1,2,3,4>>), + ?line ok = complex_or_6({false,false}, <<1,2,3,4>>), + ?line ok = complex_or_6({false,true}, <<1>>), + ?line ok = complex_or_6({true,false}, {1}), + ?line ok = complex_or_6({true,true}, {1}), + + ?line error = complex_or_6({false,false}, {1}), + + ?line error = complex_or_6({true}, {1,2,3,4}), + ?line error = complex_or_6({}, {1,2,3,4}), + ?line error = complex_or_6([], {1,2,3,4}), + ?line error = complex_or_6([], {1,2,3,4}), + ?line error = complex_or_6({true,false}, klurf), + + ok. + +complex_or_1(A, B) -> + if + ((3 < size(A)) and (size(A) < 9)) or + ((2 < size(B)) and (size(B) < 7)) -> ok; + true -> error + end. + +complex_or_2(Tuple) -> + if + element(1, Tuple) or not (size(element(2, Tuple)) > 3) -> ok; + true -> error + end. + +complex_or_3(A, B) -> + if + not (size(B) > 3) or element(1, A) -> ok; + true -> error + end. + +complex_or_4(A, B) -> + if + not (is_tuple(A) and (size(A) > 3)) or element(1, B) -> ok; + true -> error + end. + +complex_or_5(A, B) -> + if + not (is_tuple(A) or (size(A) > 3)) or not element(1, B) -> ok; + true -> error + end. + +complex_or_6(A, B) -> + if + not (not element(1, A) and not element(2, A)) or + not (not (size(B) > 3)) -> ok; + true -> error + end. + +and_guard(Config) when is_list(Config) -> + + %% 'and' combinations of literal true/false. + + ?line check(fun() -> if true and false -> ok; true -> error end end, error), + ?line check(fun() -> if false and true -> ok; true -> error end end, error), + ?line check(fun() -> if true and true -> ok end end, ok), + ?line check(fun() -> if false and false -> ok; true -> error end end, error), + + ?line check(fun() -> if glurf and true -> ok; true -> error end end, error), + ?line check(fun() -> if true and glurf -> ok; true -> error end end, error), + ?line check(fun() -> if glurf and glurf -> ok; true -> error end end, error), + + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if true and false -> ok; + false and true -> ok; + false and false -> ok + end), + exit + end, exit), + + %% 'and' combinations of true/false in variables. + + True = id(true), + False = id(false), + + ?line check(fun() -> if True and False -> ok; true -> error end end, error), + ?line check(fun() -> if False and True -> ok; true -> error end end, error), + ?line check(fun() -> if True and True -> ok end end, ok), + ?line check(fun() -> if False and False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True and False -> ok; + False and True -> ok; + False and False -> ok + end), + exit + end, exit), + + %% 'and' combinations of true/false and a non-boolean in variables. + + Glurf = id(glurf), + + ?line check(fun() -> if True and Glurf -> ok; true -> error end end, error), + ?line check(fun() -> if Glurf and True -> ok; true -> error end end, error), + ?line check(fun() -> if True and True -> ok end end, ok), + ?line check(fun() -> if Glurf and Glurf -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True and Glurf -> ok; + Glurf and True -> ok; + Glurf and Glurf -> ok + end), + exit + end, exit), + + %% 'and' combinations of true/false with errors. + ATuple = id({a,b,c}), + + ?line check(fun() -> if True and element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> if element(42, ATuple) and True -> ok; + true -> error end end, error), + ?line check(fun() -> if True and True -> ok end end, ok), + ?line check(fun() -> if element(42, ATuple) and element(42, ATuple) -> ok; + true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = + (catch if True and element(42, ATuple) -> ok; + element(42, ATuple) and True -> ok; + element(42, ATuple) and element(42, ATuple) -> ok + end), + exit + end, exit), + + ?line ok = relprod({'Set',a,b}, {'Set',a,b}), + + ok. + +relprod(R1, R2) when (erlang:size(R1) =:= 3) and (erlang:element(1,R1) =:= 'Set'), (erlang:size(R2) =:= 3) and (erlang:element(1,R2) =:= 'Set') -> + ok. + + +xor_guard(Config) when is_list(Config) -> + + %% 'xor' combinations of literal true/false. + ?line check(fun() -> if true xor false -> ok end end, ok), + ?line check(fun() -> if false xor true -> ok end end, ok), + ?line check(fun() -> if true xor true -> ok; true -> error end end, error), + ?line check(fun() -> if false xor false -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if false xor false -> ok end), + exit + end, exit), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if true xor true -> ok end), + exit + end, exit), + + + %% 'xor' combinations using variables containing true/false. + + True = id(true), + False = id(false), + + ?line check(fun() -> if True xor False -> ok end end, ok), + ?line check(fun() -> if False xor True -> ok end end, ok), + ?line check(fun() -> if True xor True -> ok; true -> error end end, error), + ?line check(fun() -> if False xor False -> ok; true -> error end end, error), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if False xor False -> ok end), + exit + end, exit), + ?line check(fun() -> + {'EXIT',{if_clause,_}} = (catch if True xor True -> ok end), + exit + end, exit), + + ok. + +more_xor_guards(Config) when is_list(Config) -> + True = id(true), + False = id(false), + ATuple = id({false,true,gurka}), + + ?line check(fun() -> + if element(42, ATuple) xor False -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if False xor element(42, ATuple) xor False -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(18, ATuple) xor element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if True xor element(42, ATuple) -> ok; + true -> error end + end, error), + + ?line check(fun() -> + if element(42, ATuple) xor True -> ok; + true -> error end + end, error), + ok. + +build_in_guard(Config) when is_list(Config) -> + SubBin = <<5.0/float>>, + ?line B = <<1,SubBin/binary,3.5/float>>, + ?line if + B =:= <<1,SubBin/binary,3.5/float>> -> ok + end. + +old_guard_tests(Config) when list(Config) -> + %% Check that all the old guard tests are still recognized. + ?line list = og(Config), + ?line atom = og(an_atom), + ?line binary = og(<<1,2>>), + ?line float = og(3.14), + ?line integer = og(43), + ?line a_function = og(fun() -> ok end), + ?line pid = og(self()), + ?line reference = og(make_ref()), + ?line tuple = og({}), + + ?line number = on(45.333), + ?line number = on(-19), + ok. + +og(V) when atom(V) -> atom; +og(V) when binary(V) -> binary; +og(V) when float(V) -> float; +og(V) when integer(V) -> integer; +og(V) when function(V) -> a_function; +og(V) when list(V) -> list; +og(V) when pid(V) -> pid; +og(V) when port(V) -> port; +og(V) when reference(V) -> reference; +og(V) when tuple(V) -> tuple; +og(_) -> what. + +on(V) when number(V) -> number; +on(_) -> not_number. + +gbif(Config) when is_list(Config) -> + ?line error = gbif_1(1, {false,true}), + ?line ok = gbif_1(2, {false,true}), + ok. + +gbif_1(P, T) when element(P, T) -> ok; +gbif_1(_, _) -> error. + + +t_is_boolean(Config) when is_list(Config) -> + ?line true = is_boolean(true), + ?line true = is_boolean(false), + ?line true = is_boolean(id(true)), + ?line true = is_boolean(id(false)), + + ?line false = is_boolean(glurf), + ?line false = is_boolean(id(glurf)), + + ?line false = is_boolean([]), + ?line false = is_boolean(id([])), + ?line false = is_boolean(42), + ?line false = is_boolean(id(-42)), + + ?line false = is_boolean(math:pi()), + ?line false = is_boolean(384793478934378924978439789873478934897), + + ?line false = is_boolean(id(self())), + ?line false = is_boolean(id({x,y,z})), + ?line false = is_boolean(id([a,b,c])), + ?line false = is_boolean(id(make_ref())), + ?line false = is_boolean(id(<<1,2,3>>)), + + ?line ok = bool(true), + ?line ok = bool(false), + ?line ok = bool(id(true)), + ?line ok = bool(id(false)), + + ?line error = bool(glurf), + ?line error = bool(id(glurf)), + + ?line error = bool([]), + ?line error = bool(id([])), + ?line error = bool(42), + ?line error = bool(id(-42)), + + ?line error = bool(math:pi()), + ?line error = bool(384793478934378924978439789873478934897), + + ?line error = bool(id(self())), + ?line error = bool(id({x,y,z})), + ?line error = bool(id([a,b,c])), + ?line error = bool(id(make_ref())), + ?line error = bool(id(<<1,2,3>>)), + + ok. + +bool(X) when is_boolean(X) -> ok; +bool(_) -> error. + + +is_function_2(Config) when is_list(Config) -> + true = is_function(id(fun ?MODULE:all/1), 1), + true = is_function(id(fun() -> ok end), 0), + false = is_function(id(fun ?MODULE:all/1), 0), + false = is_function(id(fun() -> ok end), 1), + + F = fun(_) -> ok end, + if + is_function(F, 1) -> ok + end. + +tricky(Config) when is_list(Config) -> + ?line not_ok = tricky_1(1, 2), + ?line not_ok = tricky_1(1, blurf), + ?line not_ok = tricky_1(foo, 2), + ?line not_ok = tricky_1(a, b), + + ?line false = rb(100000, [1], 42), + ?line true = rb(100000, [], 42), + ?line true = rb(555, [a,b,c], 19), + ok. + +tricky_1(X, Y) when abs((X == 1) or (Y == 2)) -> ok; +tricky_1(_, _) -> not_ok. + +%% From dets_v9:read_buckets/11, simplified. + +rb(Size, ToRead, SoFar) when SoFar + Size < 81920; ToRead == [] -> true; +rb(_, _, _) -> false. + + +-define(T(Op,A,B), + ok = if A Op B -> ok; true -> error end, + ok = if not (A Op B) -> error; true -> ok end, + (fun(X, Y, True, False) -> + ok = if X Op Y -> ok; true -> error end, + ok = if False; X Op Y; False -> ok; true -> error end, + ok = if X Op Y, True -> ok; true -> error end, + ok = if not (X Op Y) -> error; true -> ok end, + ok = if False; not (X Op Y); False -> error; true -> ok end + end)(id(A), id(B), id(true), id(false))). + +-define(F(Op,A,B), + ok = if A Op B -> error; true -> ok end, + ok = if not (A Op B) -> ok; true -> error end, + (fun(X, Y, True, False) -> + ok = if X Op Y -> error; true -> ok end, + ok = if False; X Op Y; False -> error; true -> ok end, + ok = if not (X Op Y); False -> ok; true -> error end, + ok = if not (X Op Y), True -> ok; true -> error end + end)(id(A), id(B), id(true), id(false))). + + +rel_ops(Config) when is_list(Config) -> + ?line ?T(=/=, 1, 1.0), + ?line ?F(=/=, 2, 2), + ?line ?F(=/=, {a}, {a}), + + ?line ?F(/=, a, a), + ?line ?F(/=, 0, 0.0), + ?line ?T(/=, 0, 1), + ?line ?F(/=, {a}, {a}), + + ?line ?T(==, 1, 1.0), + ?line ?F(==, a, {}), + + ?line ?F(=:=, 1, 1.0), + ?line ?T(=:=, 42.0, 42.0), + + ?line ?F(>, a, b), + ?line ?T(>, 42, 1.0), + ?line ?F(>, 42, 42.0), + + ?line ?T(<, a, b), + ?line ?F(<, 42, 1.0), + ?line ?F(<, 42, 42.0), + + ?line ?T(=<, 1.5, 5), + ?line ?F(=<, -9, -100.344), + ?line ?T(=<, 42, 42.0), + + ?line ?T(>=, 42, 42.0), + ?line ?F(>=, a, b), + ?line ?T(>=, 1.0, 0), + + ok. + +-undef(TestOp). + +basic_andalso_orelse(Config) when is_list(Config) -> + ?line T = id({type,integers,23,42}), + ?line 65 = if + ((element(1, T) =:= type) andalso (size(T) =:= 4) andalso + element(2, T) == integers) -> + element(3, T) + element(4, T); + true -> error + end, + ?line 65 = case [] of + [] when ((element(1, T) =:= type) andalso (size(T) =:= 4) andalso + element(2, T) == integers) -> + element(3, T) + element(4, T) + end, + + ?line 42 = basic_rt({type,integers,40,2}), + ?line 5.0 = basic_rt({vector,{3.0,4.0}}), + ?line 20 = basic_rt(['+',3,7]), + ?line {'Set',a,b} = basic_rt({{'Set',a,b},{'Set',a,b}}), + ?line 12 = basic_rt({klurf,4}), + + ?line error = basic_rt({type,integers,40,2,3}), + ?line error = basic_rt({kalle,integers,40,2}), + ?line error = basic_rt({kalle,integers,40,2}), + ?line error = basic_rt({1,2}), + ?line error = basic_rt([]), + + RelProdBody = + fun(R1, R2) -> + if + (erlang:size(R1) =:= 3) andalso (erlang:element(1,R1) =:= 'Set'), + (erlang:size(R2) =:= 3) andalso (erlang:element(1,R2) =:= 'Set') -> + ok + end + end, + + ?line ok = RelProdBody({'Set',a,b}, {'Set',a,b}), + ok. + +basic_rt(T) when is_tuple(T) andalso size(T) =:= 4 andalso element(1, T) =:= type andalso + element(2, T) == integers -> + element(3, T) + element(4, T); +basic_rt(T) when is_tuple(T) andalso size(T) =:= 2 andalso element(1, T) =:= vector -> + {X,Y} = element(2, T), + if + is_float(X), is_float(Y) -> + math:sqrt(X*X+Y*Y) + end; +basic_rt(['+',A,B]) -> + 2*id(A+B); +basic_rt({R1,R2}) when erlang:size(R1) =:= 3 andalso erlang:element(1,R1) =:= 'Set', + erlang:size(R2) =:= 3 andalso erlang:element(1,R2) =:= 'Set' -> + R1 = id(R1), + R2 = id(R2), + R1; +basic_rt(T) when is_tuple(T) andalso size(T) =:= 2 andalso element(1, T) =:= klurf -> + 3*id(element(2, T)); +basic_rt(_) -> + error. + +traverse_dcd(Config) when is_list(Config) -> + L0 = [{log_header,dcd_log,"1.0",a,b,c},{log_header,dcd_log,"2.0",a,b,c}, + {log_header,dcd_log,"0.0",a,b,c},blurf], + {cont,[{log_header,dcd_log,"0.0",a,b,c},blurf],log,funny} = + traverse_dcd({cont,L0}, log, funny), + L1 = [{log_header,dcd_log,"1.0"}], + {cont,L1,log,funny} = traverse_dcd({cont,L1}, log, funny), + L2 = [{a,tuple}], + {cont,L2,log,funny} = traverse_dcd({cont,L2}, log, funny), + ok. + +%% The function starts out with 3 arguments in {x,0}, {x,1}, {x,2}. +%% The outer match of a two tuple will places the first element in {x,3} and +%% second in {x,4}. The guard for the first clause must make ensure that all of those +%% registers are restored befor entering the second clause. +%% +%% (From mnesia_checkpoint.erl, modified.) + +traverse_dcd({Cont,[LogH|Rest]},Log,Fun) + when is_tuple(LogH) andalso size(LogH) =:= 6 andalso element(1, LogH) =:= log_header +andalso erlang:element(2,LogH) == dcd_log, +is_tuple(LogH) andalso size(LogH) =:= 6 andalso element(1, LogH) =:= log_header +andalso erlang:element(3,LogH) >= "1.0" -> + traverse_dcd({Cont,Rest},Log,Fun); +traverse_dcd({Cont,Recs},Log,Fun) -> + {Cont,Recs,Log,Fun}. + + +check_qlc_hrl(Config) when is_list(Config) -> + St = {r1,false,dum}, + ?line foo = cqlc(qlc, q, [{lc,1,2,3}], St), + ?line foo = cqlc(qlc, q, [{lc,1,2,3},b], St), + ?line St = cqlc(qlc, q, [], St), + ?line St = cqlc(qlc, blurf, [{lc,1,2,3},b], St), + ?line St = cqlc(q, q, [{lc,1,2,3},b], St), + ?line St = cqlc(qlc, q, [{lc,1,2,3},b,c], St), + ?line St = cqlc(qlc, q, [a,b], St), + ?line {r1,true,kalle} = cqlc(qlc, q, [{lc,1,2,3},b], {r1,true,kalle}), + ok. + +%% From erl_lint.erl; original name was check_qlc_hrl/4. +cqlc(M, F, As, St) -> + Arity = length(As), + case As of + [{lc,_L,_E,_Qs}|_] when M =:= qlc, F =:= q, + Arity < 3, + not (((element(1, St) =:= r1) orelse fail) and (size(St) =:= 3) and element(2, St)) -> + foo; + _ -> + St + end. + + + +%% Call this function to turn off constant propagation. +id(I) -> I. + +check(F, Result) -> + case F() of + Result -> ok; + Other -> + io:format("Expected: ~p\n", [Result]), + io:format(" Got: ~p\n", [Other]), + test_server:fail() + end. diff --git a/lib/debugger/test/int_SUITE.erl b/lib/debugger/test/int_SUITE.erl new file mode 100644 index 0000000000..0326325888 --- /dev/null +++ b/lib/debugger/test/int_SUITE.erl @@ -0,0 +1,277 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(int_SUITE). +-include("test_server.hrl"). + +%% Test server specific exports +-export([all/1]). +-export([init_per_testcase/2, end_per_testcase/2]). + +%% Test cases +-export([interpret/1, guards/1, list_suite/1, interpretable/1]). +-export([append/1, append_1/1, append_2/1, member/1, reverse/1]). + +%% Default timetrap timeout (set in init_per_testcase) +-define(default_timeout, ?t:minutes(1)). + +init_per_testcase(interpretable, Config) -> + ?line Dog=test_server:timetrap(?default_timeout), + [{watchdog, Dog}|Config]; +init_per_testcase(_Case, Config) -> + + %% Interpret some existing and non-existing modules + ?line DataDir = ?config(data_dir, Config), + ?line {module, lists1} = int:i(filename:join([DataDir,lists1])), + ?line {module, guards} = int:i(filename:join([DataDir,guards])), + + ?line Dog=test_server:timetrap(?default_timeout), + [{watchdog, Dog}|Config]. + +end_per_testcase(interpretable, Config) -> + ?line Dog=?config(watchdog, Config), + ?line test_server:timetrap_cancel(Dog), + ok; +end_per_testcase(_Case, Config) -> + + %% Quit interpreting + ?line ok = int:n(lists1), + ?line ok = int:n(guards), + + ?line Dog=?config(watchdog, Config), + ?line test_server:timetrap_cancel(Dog), + ?line ok. + +all(suite)-> + [interpret, guards, list_suite, interpretable]. + +interpret(suite) -> + []; +interpret(doc) -> + ["Interpreting modules"]; +interpret(Config) when is_list(Config) -> + ?line int:n(int:interpreted()), + + %% Interpret some existing and non-existing modules + ?line DataDir = ?config(data_dir, Config), + ?line {module, lists1} = int:i(filename:join([DataDir,lists1])), + ?line {module, ordsets1} = int:i(filename:join([DataDir,ordsets1])), + ?line error = int:i(non_existent_module), + + %% Check that the interpreter has the right view. + ?line ExpectedResult = lists:sort([lists1, ordsets1]), + ?line Result = int:interpreted(), + ?line ExpectedResult = lists:sort(Result), + + %% Uniterpret the modules. + ?line ok = int:n(non_existent_module), + ?line ok = int:n(lists1), + ?line [ordsets1] = int:interpreted(), + ?line ok = int:n("ordsets1"), + ?line [] = int:interpreted(), + + ok. + +guards(suite) -> + []; +guards(doc) -> + "Evaluate guards."; +guards(Config) when is_list(Config) -> + ok = guards:guards(). + + +list_suite(suite) -> + [append, reverse, member]. + +append(doc) -> + ["Tests lists1:append/1 & lists1:append/2"]; +append(suite) -> + [append_1, append_2]. + +append_1(suite) -> + []; +append_1(doc) -> + []; +append_1(Config) when is_list(Config) -> + ?line test_server:format("In append_1~n"), + ?line test_server:format("code:which(lists1)=~p~n", + [code:which(lists1)]), + ?line test_server:format("lists1:append([a],[b])=~p~n", + [spawn_eval(lists1,append,[[a],[b]])]), + + ?line "abcdef"=spawn_eval(lists1,append,[["abc","def"]]), + ?line [hej, du,[glade, [bagare]]]= + spawn_eval(lists1,append,[[[hej], [du], [[glade, [bagare]]]]]), + ?line [10, [elem]]=spawn_eval(lists1,append,[[[10], [[elem]]]]), + ok. + +append_2(suite) -> + []; +append_2(doc) -> + []; +append_2(Config) when is_list(Config) -> + ?line test_server:format("In append_2~n"), + ?line test_server:format("code:which(lists1)=~p~n", + [code:which(lists1)]), + + ?line "abcdef"=spawn_eval(lists1,append,["abc", "def"]), + ?line [hej, du]=spawn_eval(lists1,append,[[hej], [du]]), + ?line [10, [elem]]=spawn_eval(lists1,append,[[10], [[elem]]]), + ok. + +reverse(suite) -> + []; +reverse(doc) -> + []; +reverse(Config) when is_list(Config) -> + ?line ok=reverse_test(0), + ?line ok=reverse_test(1), + ?line ok=reverse_test(2), + ?line ok=reverse_test(537), + ok. + +reverse_test(0) -> + case spawn_eval(lists1,reverse,[[]]) of + [] -> + ok; + _Other -> + error + end; +reverse_test(Num) -> + List=spawn_eval(lists1,reverse, + [['The Element'|lists1:duplicate(Num, 'Ele')]]), + case spawn_eval(lists1,reverse,[List]) of + ['The Element'|_Rest] -> + ok; + _Other -> + error + end. + +member(suite) -> + []; +member(doc) -> + ["Tests the lists1:member() implementation. The function " + "is `non-blocking', and only processes 2000 elements " + "at a time.", + "This test case depends on lists1:reverse() to work, " + "wich is tested in a separate test case."]; +member(Config) when list(Config) -> + ?line ok=member_test(0), + ?line ok=member_test(1), + ?line ok=member_test(100), + ?line ok=member_test(537), + ok. + +member_test(0) -> + case spawn_eval(lists1,member,['The Element', []]) of + false -> + ok; + true -> + {error, 'Found (!?)'} + end; +member_test(Num) -> + List=spawn_eval(lists1,reverse, + [['The Element'|spawn_eval(lists1,duplicate, + [Num, 'Elem'])]]), + case spawn_eval(lists1,member,['The Element', List]) of + true -> + ok; + false -> + {error, not_found} + end. + +spawn_eval(M,F,A) -> + Self = self(), + spawn(fun() -> evaluator(Self, M,F,A) end), + receive + Result -> + Result + end. + +evaluator(Pid, M,F,A) -> + Pid ! (catch apply(M,F,A)). + +interpretable(suite) -> + []; +interpretable(doc) -> + ["Test int:interpretable/1"]; +interpretable(Config) when is_list(Config) -> + + %% First make sure that 'lists1' is not loaded + case code:is_loaded(lists1) of + {file, _Loaded} -> + ?line code:purge(lists1), + ?line code:delete(lists1), + ?line code:purge(lists1); + false -> ignore + end, + + %% true + ?line DataDir = filename:dirname(?config(data_dir, Config)), + ?line true = code:add_patha(DataDir), + ?line true = int:interpretable(lists1), + ?line true = int:interpretable(filename:join([DataDir,lists1])), + ?line true = code:del_path(DataDir), + + %% {error, no_src} + ?line PrivDir = filename:join(?config(priv_dir, Config), ""), + ?line {ok, _} = file:copy(filename:join([DataDir,"lists1.beam"]), + filename:join([PrivDir,"lists1.beam"])), + ?line true = code:add_patha(PrivDir), + + ?line {error, no_src} = int:interpretable(lists1), + ?line ok = file:delete(filename:join([PrivDir,"lists1.beam"])), + + %% {error, no_beam} + Src = filename:join([PrivDir,"lists1.erl"]), + ?line {ok, _} = file:copy(filename:join([DataDir,"lists1.erl"]), + Src), + ?line {error, no_beam} = int:interpretable(Src), + + %% {error, no_debug_info} + ?line {ok, _} = compile:file(Src, [{outdir,PrivDir}]), + ?line {error, no_debug_info} = int:interpretable(Src), + ?line {error, no_debug_info} = int:interpretable(lists1), + ?line ok = file:delete(Src), + ?line true = code:del_path(PrivDir), + + %% {error, badarg} + ?line {error, badarg} = int:interpretable(pride), + ?line {error, badarg} = int:interpretable("prejudice.erl"), + + %% {error, {app,App}} + ?line {error, {app,_}} = int:interpretable(file), + ?line {error, {app,_}} = int:interpretable(lists), + ?line {error, {app,_}} = int:interpretable(gs), + ?line case int:interpretable(dbg_ieval) of + {error, {app,_}} -> + ok; + {error, badarg} -> + case code:which(dbg_ieval) of + cover_compiled -> + ok; + Other1 -> + ?line ?t:fail({unexpected_result, Other1}) + end; + Other2 -> + ?line ?t:fail({unexpected_result, Other2}) + end, + + ok. diff --git a/lib/debugger/test/int_SUITE_data/Makefile.src b/lib/debugger/test/int_SUITE_data/Makefile.src new file mode 100644 index 0000000000..95b96b5d00 --- /dev/null +++ b/lib/debugger/test/int_SUITE_data/Makefile.src @@ -0,0 +1,39 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +EFLAGS=+debug_info +all: guards.@EMULATOR@ lists1.@EMULATOR@ my_lists.@EMULATOR@ \ + ordsets1.@EMULATOR@ test.@EMULATOR@ test1.@EMULATOR@ + +guards.@EMULATOR@: guards.erl + erlc $(EFLAGS) guards.erl + +lists1.@EMULATOR@: lists1.erl + erlc $(EFLAGS) lists1.erl + +my_lists.@EMULATOR@: my_lists.erl + erlc $(EFLAGS) my_lists.erl + +ordsets1.@EMULATOR@: ordsets1.erl + erlc $(EFLAGS) ordsets1.erl + +test.@EMULATOR@: test.erl + erlc $(EFLAGS) test.erl + +test1.@EMULATOR@: test1.erl + erlc $(EFLAGS) test1.erl diff --git a/lib/debugger/test/int_SUITE_data/guards.erl b/lib/debugger/test/int_SUITE_data/guards.erl new file mode 100644 index 0000000000..c847bb6a8c --- /dev/null +++ b/lib/debugger/test/int_SUITE_data/guards.erl @@ -0,0 +1,108 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(guards). + +-export([guards/0]). + +guards() -> + ok = t(), + ok = f(), + ok = ct(1), + ok = multi(1), + ok = multi(2), + ok = multi(3). + +%% The following tests are always true. +t() when integer(42) -> + ok; +t() when float(2.0) -> + ok; +t() when number(7) -> + ok; +t() when number(3.14) -> + ok; +t() when atom(error) -> + ok; +t() when list([a]) -> + ok; +t() when tuple({}) -> + ok; +t() when tuple({1, 2}) -> + ok. + +%% The following tests are always false. +f() when integer(a) -> + ok; +f() when float(b) -> + ok; +f() when number(c) -> + ok; +f() when atom(42) -> + ok; +f() when list(33) -> + ok; +f() when list({}) -> + ok; +f() when list({1, 2}) -> + ok; +f() when tuple(33) -> + ok; +f() when tuple([a]) -> + ok; +f() when tuple([]) -> + ok; +f() when tuple(35) -> + ok; +f() -> + ok. + +%% The following tests are always true. +ct(X) -> + case X of + Y when integer(42) -> + ok; + Y when float(2.0) -> + ok; + Y when number(7) -> + ok; + Y when number(3.14) -> + ok; + Y when atom(error) -> + ok; + Y when list([a]) -> + ok; + Y when tuple({}) -> + ok; + Y when tuple({1, 2}) -> + ok + end. + +multi(X) -> + case X of + Y when float(Y) ; integer(Y) -> + ok; + Y when Y > 1, Y < 10 ; atom(Y) -> + ok; + Y when Y == 4, number(Y) ; list(Y) -> + pannkaka; + Y when Y==3 ; Y==5 ; Y==6 -> + ok + end. diff --git a/lib/debugger/test/int_SUITE_data/lists1.erl b/lib/debugger/test/int_SUITE_data/lists1.erl new file mode 100644 index 0000000000..0214983c11 --- /dev/null +++ b/lib/debugger/test/int_SUITE_data/lists1.erl @@ -0,0 +1,469 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Purpose : Basic lists processing functions. + +-module(lists1). + + +-export([member/2, append/2, append/1, subtract/2, reverse/1, reverse/2, + nth/2, nthtail/2, prefix/2, suffix/2, last/1, + seq/2, seq/3, sum/1, duplicate/2, min/1, max/1, sublist/2, sublist/3, + delete/2, sort/1, merge/2, concat/1, + flatten/1, flatten/2, flat_length/1, flatlength/1, + keymember/3, keysearch/3, keydelete/3, keyreplace/4, + keysort/2, keymerge/3, keymap/3, keymap/4]). + +-export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2,zf/2, + mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,splitwith/2]). +-export([all/3,any/3,map/3,flatmap/3,foldl/4,foldr/4,filter/3,zf/3, + mapfoldl/4,mapfoldr/4,foreach/3]). + +%% member(X, L) -> (true | false) +%% test if X is a member of the list L + +member(X, [X|_]) -> true; +member(X, [_|Y]) -> + member(X, Y); +member(X, []) -> false. + +%% append(X, Y) appends lists X and Y + +append(L1, L2) -> L1 ++ L2. + +%% append(L) appends the list of lists L + +append([E]) -> E; +append([H|T]) -> H ++ append(T); +append([]) -> []. + +%% subtract(List1, List2) subtract elements in List2 form List1. + +subtract(L1, L2) -> L1 -- L2. + +%% reverse(L) reverse all elements in the list L + +reverse(X) -> reverse(X, []). + +reverse([H|T], Y) -> + reverse(T, [H|Y]); +reverse([], X) -> X. + +%% nth(N, L) returns the N`th element of the list L +%% nthtail(N, L) returns the N`th tail of the list L + +nth(1, [H|T]) -> H; +nth(N, [_|T]) when N > 1 -> + nth(N - 1, T). + +nthtail(1, [H|T]) -> T; +nthtail(N, [H|T]) when N > 1 -> + nthtail(N - 1, T); +nthtail(0, L) when list(L) -> L. + +%% prefix(Prefix, List) -> (true | false) + +prefix([X|PreTail], [X|Tail]) -> + prefix(PreTail, Tail); +prefix([], List) -> true; +prefix(_,_) -> false. + + +%% suffix(Suffix, List) -> (true | false) + +suffix(Suffix, Suffix) -> true; +suffix(Suffix, [_|Tail]) -> + suffix(Suffix, Tail); +suffix(Suffix, []) -> false. + +%% last(List) returns the last element in a list. + +last([E]) -> E; +last([E|Es]) -> + last(Es). + +%% seq(Min, Max) -> [Min,Min+1, ..., Max] +%% seq(Min, Max, Incr) -> [Min,Min+Incr, ..., Max] +%% returns the sequence Min..Max +%% Min <= Max and Min and Max must be integers + +seq(Min, Max) when integer(Min), integer(Max), Min =< Max -> + seq(Min, Max, 1, []). + +seq(Min, Max, Incr) -> + seq(Min, Min + ((Max-Min) div Incr) * Incr, Incr, []). + +seq(Min, Min, I, L) -> [Min|L]; +seq(Min, Max, I, L) -> seq(Min, Max-I, I, [Max|L]). + +%% sum(L) suns the sum of the elements in L + +sum(L) -> sum(L, 0). +sum([H|T], Sum) -> sum(T, Sum + H); +sum([], Sum) -> Sum. + +%% duplicate(N, X) -> [X,X,X,.....,X] (N times) +%% return N copies of X + +duplicate(N, X) when integer(N), N >= 0 -> duplicate(N, X, []). + +duplicate(0, _, L) -> L; +duplicate(N, X, L) -> duplicate(N-1, X, [X|L]). + + +%% min(L) -> returns the minimum element of the list L + +min([H|T]) -> min(T, H). + +min([H|T], Min) when H < Min -> min(T, H); +min([_|T], Min) -> min(T, Min); +min([], Min) -> Min. + +%% max(L) -> returns the maximum element of the list L + +max([H|T]) -> max(T, H). + +max([H|T], Max) when H > Max -> max(T, H); +max([_|T], Max) -> max(T, Max); +max([], Max) -> Max. + +%% sublist(List, Start, Length) +%% Returns the sub-list starting at Start of length Length. + +sublist(List, S, L) when L >= 0 -> + sublist(nthtail(S-1, List), L). + +sublist([H|T], L) when L > 0 -> + [H|sublist(T, L-1)]; +sublist(List, L) -> []. + +%% delete(Item, List) -> List' +%% Delete the first occurance of Item from the list L. + +delete(Item, [Item|Rest]) -> Rest; +delete(Item, [H|Rest]) -> + [H|delete(Item, Rest)]; +delete(Item, []) -> []. + +%% sort(L) -> sorts the list L + +sort([X]) -> [X]; +sort([]) -> []; +sort(X) -> split_and_sort(X, [], []). + +split_and_sort([A,B|T], X, Y) -> + split_and_sort(T, [A|X], [B|Y]); +split_and_sort([H], X, Y) -> + split_and_sort([], [H|X], Y); +split_and_sort([], X, Y) -> + merge(sort(X), sort(Y), []). + +%% merge(X, Y) -> L +%% merges two sorted lists X and Y + +merge(X, Y) -> merge(X, Y, []). + +merge([H1|T1], [H2|T2], L) when H1 < H2 -> + merge(T1, [H2|T2], [H1|L]); +merge(T1, [H2|T2], L) -> + merge(T1, T2, [H2|L]); +merge([H|T], T2, L) -> + merge(T, T2, [H|L]); +merge([], [], L) -> + reverse(L). + +%% concat(L) concatinate the list representation of the elements +%% in L - the elements in L can be atoms, integers of strings. +%% Returns a list of characters. + +concat(List) -> + flatmap(fun thing_to_list/1, List). + +thing_to_list(X) when integer(X) -> integer_to_list(X); +thing_to_list(X) when float(X) -> float_to_list(X); +thing_to_list(X) when atom(X) -> atom_to_list(X); +thing_to_list(X) when list(X) -> X. %Assumed to be a string + +%% flatten(List) +%% flatten(List, Tail) +%% Flatten a list, adding optional tail. + +flatten(List) -> + flatten(List, [], []). + +flatten(List, Tail) -> + flatten(List, [], Tail). + +flatten([H|T], Cont, Tail) when list(H) -> + flatten(H, [T|Cont], Tail); +flatten([H|T], Cont, Tail) -> + [H|flatten(T, Cont, Tail)]; +flatten([], [H|Cont], Tail) -> + flatten(H, Cont, Tail); +flatten([], [], Tail) -> + Tail. + +%% flat_length(List) (undocumented can be rmove later) +%% Calculate the length of a list of lists. + +flat_length(List) -> flatlength(List). + +%% flatlength(List) +%% Calculate the length of a list of lists. + +flatlength(List) -> + flatlength(List, 0). + +flatlength([H|T], L) when list(H) -> + flatlength(H, flatlength(T, L)); +flatlength([H|T], L) -> + flatlength(T, L + 1); +flatlength([], L) -> L. + +%% keymember(Key, Index, [Tuple]) +%% keysearch(Key, Index, [Tuple]) +%% keydelete(Key, Index, [Tuple]) +%% keyreplace(Key, Index, [Tuple], NewTuple) +%% keysort(Index, [Tuple]) +%% keymerge(Index, [Tuple], [Tuple]) +%% keymap(Function, Index, [Tuple]) +%% keymap(Function, ExtraArgs, Index, [Tuple]) + +keymember(Key, N, [T|Ts]) when element(N, T) == Key -> true; +keymember(Key, N, [T|Ts]) -> + keymember(Key, N, Ts); +keymember(Key, N, []) -> false. + +keysearch(Key, N, [H|T]) when element(N, H) == Key -> + {value, H}; +keysearch(Key, N, [H|T]) -> + keysearch(Key, N, T); +keysearch(Key, N, []) -> false. + +keydelete(Key, N, [H|T]) when element(N, H) == Key -> T; +keydelete(Key, N, [H|T]) -> + [H|keydelete(Key, N, T)]; +keydelete(Key, N, []) -> []. + +keyreplace(Key, Pos, [Tup|Tail], New) when element(Pos, Tup) == Key -> + [New|Tail]; +keyreplace(Key, Pos, [H|T], New) -> + [H|keyreplace(Key, Pos, T, New)]; +keyreplace(Key, Pos, [], New) -> []. + +keysort(Index, [X]) -> [X]; +keysort(Index, []) -> []; +keysort(Index, X) -> split_and_keysort(X, [], [], Index). + +split_and_keysort([A,B|T], X, Y, Index) -> + split_and_keysort(T, [A|X], [B|Y], Index); +split_and_keysort([H], X, Y, Index) -> + split_and_keysort([], [H|X], Y, Index); +split_and_keysort([], X, Y, Index) -> + keymerge(Index, keysort(Index, X), keysort(Index, Y), []). + +keymerge(Index, X, Y) -> keymerge(Index, X, Y, []). + +keymerge(I, [H1|T1], [H2|T2], L) when element(I, H1) < element(I, H2) -> + keymerge(I, T1, [H2|T2], [H1|L]); +keymerge(Index, T1, [H2|T2], L) -> + keymerge(Index,T1, T2, [H2|L]); +keymerge(Index,[H|T], T2, L) -> + keymerge(Index,T, T2, [H|L]); +keymerge(Index, [], [], L) -> + reverse(L). + +keymap(Fun, Index, [Tup|Tail]) -> + [setelement(Index, Tup, Fun(element(Index, Tup)))|keymap(Fun, Index, Tail)]; +keymap( _, _ , []) -> []. + +keymap(Fun, ExtraArgs, Index, [Tup|Tail]) -> + [setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))| + keymap(Fun, ExtraArgs, Index, Tail)]; +keymap( _, _ , _, []) -> []. + +%% all(Predicate, List) +%% any(Predicate, List) +%% map(Function, List) +%% flatmap(Function, List) +%% foldl(Function, First, List) +%% foldr(Function, Last, List) +%% filter(Predicate, List) +%% zf(Function, List) +%% mapfoldl(Function, First, List) +%% mapfoldr(Function, Last, List) +%% foreach(Function, List) +%% takewhile(Predicate, List) +%% dropwhile(Predicate, List) +%% splitwith(Predicate, List) +%% for list programming. Function here is either a 'fun' or a tuple +%% {Module,Name} and we use apply/2 to evaluate. The name zf is a joke! +%% +%% N.B. Unless where the functions actually needs it only foreach/2/3, +%% which is meant to be used for its side effects, has a defined order +%% of evaluation. +%% +%% There are also versions with an extra argument, ExtraArgs, which is a +%% list of extra arguments to each call. + +all(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> all(Pred, Tail); + false -> false + end; +all(Pred, []) -> true. + +any(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> true; + false -> any(Pred, Tail) + end; +any(Pred, []) -> false. + +map(F, List) -> [ F(E) || E <- List ]. + +flatmap(F, [Hd|Tail]) -> + F(Hd) ++ flatmap(F, Tail); +flatmap(F, []) -> []. + +foldl(F, Accu, [Hd|Tail]) -> + foldl(F, F(Hd, Accu), Tail); +foldl(F, Accu, []) -> Accu. + +foldr(F, Accu, [Hd|Tail]) -> + F(Hd, foldr(F, Accu, Tail)); +foldr(F, Accu, []) -> Accu. + +filter(Pred, List) -> [ E || E <- List, Pred(E) ]. + +zf(F, [Hd|Tail]) -> + case F(Hd) of + true -> + [Hd|zf(F, Tail)]; + {true,Val} -> + [Val|zf(F, Tail)]; + false -> + zf(F, Tail) + end; +zf(F, []) -> []. + +foreach(F, [Hd|Tail]) -> + F(Hd), + foreach(F, Tail); +foreach(F, []) -> ok. + +mapfoldl(F, Accu0, [Hd|Tail]) -> + {R,Accu1} = F(Hd, Accu0), + {Rs,Accu2} = mapfoldl(F, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl(F, Accu, []) -> {[],Accu}. + +mapfoldr(F, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr(F, Accu0, Tail), + {R,Accu2} = F(Hd, Accu1), + {[R|Rs],Accu2}; +mapfoldr(F, Accu, []) -> {[],Accu}. + +takewhile(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> [Hd|takewhile(Pred, Tail)]; + false -> [] + end; +takewhile(Pred, []) -> []. + +dropwhile(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> dropwhile(Pred, Tail); + false -> [Hd|Tail] + end; +dropwhile(Pred, []) -> []. + +splitwith(Pred, List) -> splitwith(Pred, List, []). + +splitwith(Pred, [Hd|Tail], Taken) -> + case Pred(Hd) of + true -> splitwith(Pred, Tail, [Hd|Taken]); + false -> {reverse(Taken), [Hd|Tail]} + end; +splitwith(Pred, [], Taken) -> {reverse(Taken),[]}. + +%% Versions of the above functions with extra arguments. + +all(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> all(Pred, Eas, Tail); + false -> false + end; +all(Pred, Eas, []) -> true. + +any(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> true; + false -> any(Pred, Eas, Tail) + end; +any(Pred, Eas, []) -> false. + +map(F, Eas, List) -> [ apply(F, [E|Eas]) || E <- List ]. + +flatmap(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]) ++ flatmap(F, Eas, Tail); +flatmap(F, Eas, []) -> []. + +foldl(F, Eas, Accu, [Hd|Tail]) -> + foldl(F, Eas, apply(F, [Hd,Accu|Eas]), Tail); +foldl(F, Eas, Accu, []) -> Accu. + +foldr(F, Eas, Accu, [Hd|Tail]) -> + apply(F, [Hd,foldr(F, Eas, Accu, Tail)|Eas]); +foldr(F, Eas, Accu, []) -> + Accu. + +filter(Pred, Eas, List) -> [ E || E <- List, apply(Pred, [E|Eas]) ]. + +zf(F, Eas, [Hd|Tail]) -> + case apply(F, [Hd|Eas]) of + true -> + [Hd|zf(F, Eas, Tail)]; + {true,Val} -> + [Val|zf(F, Eas, Tail)]; + false -> + zf(F, Eas, Tail) + end; +zf(F, Eas, []) -> []. + +foreach(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]), + foreach(F, Eas, Tail); +foreach(F, Eas, []) -> ok. + +mapfoldl(F, Eas, Accu0, [Hd|Tail]) -> + {R,Accu1} = apply(F, [Hd,Accu0|Eas]), + {Rs,Accu2} = mapfoldl(F, Eas, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl(F, Eas, Accu, []) -> {[],Accu}. + +mapfoldr(F, Eas, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr(F, Eas, Accu0, Tail), + {R,Accu2} = apply(F, [Hd,Accu1|Eas]), + {[R|Rs],Accu2}; +mapfoldr(F, Eas, Accu, []) -> {[],Accu}. + +%% takewhile/2, dropwhile/2 and splitwith/2 do not have versions with +%% extra arguments as this going to be discontinued. diff --git a/lib/debugger/test/int_SUITE_data/my_lists.erl b/lib/debugger/test/int_SUITE_data/my_lists.erl new file mode 100644 index 0000000000..98eb4396e3 --- /dev/null +++ b/lib/debugger/test/int_SUITE_data/my_lists.erl @@ -0,0 +1,5681 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%% A rather large file to test the attach delay. +%%% Use only the ordinary lists commands. + +-module(my_lists). + + +-export([member/2, append/2, append/1, subtract/2, reverse/1, reverse/2, + nth/2, nthtail/2, prefix/2, suffix/2, last/1, + seq/2, seq/3, sum/1, duplicate/2, min/1, max/1, sublist/2, sublist/3, + delete/2, sort/1, merge/2, concat/1, + flatten/1, flatten/2, flat_length/1, flatlength/1, + keymember/3, keysearch/3, keydelete/3, keyreplace/4, + keysort/2, keymerge/3, keymap/3, keymap/4]). + +-export([all/2,any/2,map/2,flatmap/2,foldl/3,foldr/3,filter/2,zf/2, + mapfoldl/3,mapfoldr/3,foreach/2,takewhile/2,dropwhile/2,splitwith/2]). +-export([all/3,any/3,map/3,flatmap/3,foldl/4,foldr/4,filter/3,zf/3, + mapfoldl/4,mapfoldr/4,foreach/3]). + +%% member(X, L) -> (true | false) +%% test if X is a member of the list L + +member(X, [X|_]) -> true; +member(X, [_|Y]) -> + member(X, Y); +member(X, []) -> false. + +%% append(X, Y) appends lists X and Y + +append(L1, L2) -> L1 ++ L2. + +%% append(L) appends the list of lists L + +append([E]) -> E; +append([H|T]) -> H ++ append(T); +append([]) -> []. + +%% subtract(List1, List2) subtract elements in List2 form List1. + +subtract(L1, L2) -> L1 -- L2. + +%% reverse(L) reverse all elements in the list L + +reverse(X) -> reverse(X, []). + +reverse([H|T], Y) -> + reverse(T, [H|Y]); +reverse([], X) -> X. + +%% nth(N, L) returns the N`th element of the list L +%% nthtail(N, L) returns the N`th tail of the list L + +nth(1, [H|T]) -> H; +nth(N, [_|T]) when N > 1 -> + nth(N - 1, T). + +nthtail(1, [H|T]) -> T; +nthtail(N, [H|T]) when N > 1 -> + nthtail(N - 1, T); +nthtail(0, L) when list(L) -> L. + +%% prefix(Prefix, List) -> (true | false) + +prefix([X|PreTail], [X|Tail]) -> + prefix(PreTail, Tail); +prefix([], List) -> true; +prefix(_,_) -> false. + + +%% suffix(Suffix, List) -> (true | false) + +suffix(Suffix, Suffix) -> true; +suffix(Suffix, [_|Tail]) -> + suffix(Suffix, Tail); +suffix(Suffix, []) -> false. + +%% last(List) returns the last element in a list. + +last([E]) -> E; +last([E|Es]) -> + last(Es). + +%% seq(Min, Max) -> [Min,Min+1, ..., Max] +%% seq(Min, Max, Incr) -> [Min,Min+Incr, ..., Max] +%% returns the sequence Min..Max +%% Min <= Max and Min and Max must be integers + +seq(Min, Max) when integer(Min), integer(Max), Min =< Max -> + seq(Min, Max, 1, []). + +seq(Min, Max, Incr) -> + seq(Min, Min + ((Max-Min) div Incr) * Incr, Incr, []). + +seq(Min, Min, I, L) -> [Min|L]; +seq(Min, Max, I, L) -> seq(Min, Max-I, I, [Max|L]). + +%% sum(L) suns the sum of the elements in L + +sum(L) -> sum(L, 0). +sum([H|T], Sum) -> sum(T, Sum + H); +sum([], Sum) -> Sum. + +%% duplicate(N, X) -> [X,X,X,.....,X] (N times) +%% return N copies of X + +duplicate(N, X) when integer(N), N >= 0 -> duplicate(N, X, []). + +duplicate(0, _, L) -> L; +duplicate(N, X, L) -> duplicate(N-1, X, [X|L]). + + +%% min(L) -> returns the minimum element of the list L + +min([H|T]) -> min(T, H). + +min([H|T], Min) when H < Min -> min(T, H); +min([_|T], Min) -> min(T, Min); +min([], Min) -> Min. + +%% max(L) -> returns the maximum element of the list L + +max([H|T]) -> max(T, H). + +max([H|T], Max) when H > Max -> max(T, H); +max([_|T], Max) -> max(T, Max); +max([], Max) -> Max. + +%% sublist(List, Start, Length) +%% Returns the sub-list starting at Start of length Length. + +sublist(List, S, L) when L >= 0 -> + sublist(nthtail(S-1, List), L). + +sublist([H|T], L) when L > 0 -> + [H|sublist(T, L-1)]; +sublist(List, L) -> []. + +%% delete(Item, List) -> List' +%% Delete the first occurance of Item from the list L. + +delete(Item, [Item|Rest]) -> Rest; +delete(Item, [H|Rest]) -> + [H|delete(Item, Rest)]; +delete(Item, []) -> []. + +%% sort(L) -> sorts the list L + +sort([X]) -> [X]; +sort([]) -> []; +sort(X) -> split_and_sort(X, [], []). + +split_and_sort([A,B|T], X, Y) -> + split_and_sort(T, [A|X], [B|Y]); +split_and_sort([H], X, Y) -> + split_and_sort([], [H|X], Y); +split_and_sort([], X, Y) -> + merge(sort(X), sort(Y), []). + +%% merge(X, Y) -> L +%% merges two sorted lists X and Y + +merge(X, Y) -> merge(X, Y, []). + +merge([H1|T1], [H2|T2], L) when H1 < H2 -> + merge(T1, [H2|T2], [H1|L]); +merge(T1, [H2|T2], L) -> + merge(T1, T2, [H2|L]); +merge([H|T], T2, L) -> + merge(T, T2, [H|L]); +merge([], [], L) -> + reverse(L). + +%% concat(L) concatinate the list representation of the elements +%% in L - the elements in L can be atoms, integers of strings. +%% Returns a list of characters. + +concat(List) -> + flatmap(fun thing_to_list/1, List). + +thing_to_list(X) when integer(X) -> integer_to_list(X); +thing_to_list(X) when float(X) -> float_to_list(X); +thing_to_list(X) when atom(X) -> atom_to_list(X); +thing_to_list(X) when list(X) -> X. %Assumed to be a string + +%% flatten(List) +%% flatten(List, Tail) +%% Flatten a list, adding optional tail. + +flatten(List) -> + flatten(List, [], []). + +flatten(List, Tail) -> + flatten(List, [], Tail). + +flatten([H|T], Cont, Tail) when list(H) -> + flatten(H, [T|Cont], Tail); +flatten([H|T], Cont, Tail) -> + [H|flatten(T, Cont, Tail)]; +flatten([], [H|Cont], Tail) -> + flatten(H, Cont, Tail); +flatten([], [], Tail) -> + Tail. + +%% flat_length(List) (undocumented can be rmove later) +%% Calculate the length of a list of lists. + +flat_length(List) -> flatlength(List). + +%% flatlength(List) +%% Calculate the length of a list of lists. + +flatlength(List) -> + flatlength(List, 0). + +flatlength([H|T], L) when list(H) -> + flatlength(H, flatlength(T, L)); +flatlength([H|T], L) -> + flatlength(T, L + 1); +flatlength([], L) -> L. + +%% keymember(Key, Index, [Tuple]) +%% keysearch(Key, Index, [Tuple]) +%% keydelete(Key, Index, [Tuple]) +%% keyreplace(Key, Index, [Tuple], NewTuple) +%% keysort(Index, [Tuple]) +%% keymerge(Index, [Tuple], [Tuple]) +%% keymap(Function, Index, [Tuple]) +%% keymap(Function, ExtraArgs, Index, [Tuple]) + +keymember(Key, N, [T|Ts]) when element(N, T) == Key -> true; +keymember(Key, N, [T|Ts]) -> + keymember(Key, N, Ts); +keymember(Key, N, []) -> false. + +keysearch(Key, N, [H|T]) when element(N, H) == Key -> + {value, H}; +keysearch(Key, N, [H|T]) -> + keysearch(Key, N, T); +keysearch(Key, N, []) -> false. + +keydelete(Key, N, [H|T]) when element(N, H) == Key -> T; +keydelete(Key, N, [H|T]) -> + [H|keydelete(Key, N, T)]; +keydelete(Key, N, []) -> []. + +keyreplace(Key, Pos, [Tup|Tail], New) when element(Pos, Tup) == Key -> + [New|Tail]; +keyreplace(Key, Pos, [H|T], New) -> + [H|keyreplace(Key, Pos, T, New)]; +keyreplace(Key, Pos, [], New) -> []. + +keysort(Index, [X]) -> [X]; +keysort(Index, []) -> []; +keysort(Index, X) -> split_and_keysort(X, [], [], Index). + +split_and_keysort([A,B|T], X, Y, Index) -> + split_and_keysort(T, [A|X], [B|Y], Index); +split_and_keysort([H], X, Y, Index) -> + split_and_keysort([], [H|X], Y, Index); +split_and_keysort([], X, Y, Index) -> + keymerge(Index, keysort(Index, X), keysort(Index, Y), []). + +keymerge(Index, X, Y) -> keymerge(Index, X, Y, []). + +keymerge(I, [H1|T1], [H2|T2], L) when element(I, H1) < element(I, H2) -> + keymerge(I, T1, [H2|T2], [H1|L]); +keymerge(Index, T1, [H2|T2], L) -> + keymerge(Index,T1, T2, [H2|L]); +keymerge(Index,[H|T], T2, L) -> + keymerge(Index,T, T2, [H|L]); +keymerge(Index, [], [], L) -> + reverse(L). + +keymap(Fun, Index, [Tup|Tail]) -> + [setelement(Index, Tup, Fun(element(Index, Tup)))|keymap(Fun, Index, Tail)]; +keymap( _, _ , []) -> []. + +keymap(Fun, ExtraArgs, Index, [Tup|Tail]) -> + [setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))| + keymap(Fun, ExtraArgs, Index, Tail)]; +keymap( _, _ , _, []) -> []. + +%% all(Predicate, List) +%% any(Predicate, List) +%% map(Function, List) +%% flatmap(Function, List) +%% foldl(Function, First, List) +%% foldr(Function, Last, List) +%% filter(Predicate, List) +%% zf(Function, List) +%% mapfoldl(Function, First, List) +%% mapfoldr(Function, Last, List) +%% foreach(Function, List) +%% takewhile(Predicate, List) +%% dropwhile(Predicate, List) +%% splitwith(Predicate, List) +%% for list programming. Function here is either a 'fun' or a tuple +%% {Module,Name} and we use apply/2 to evaluate. The name zf is a joke! +%% +%% N.B. Unless where the functions actually needs it only foreach/2/3, +%% which is meant to be used for its side effects, has a defined order +%% of evaluation. +%% +%% There are also versions with an extra argument, ExtraArgs, which is a +%% list of extra arguments to each call. + +all(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> all(Pred, Tail); + false -> false + end; +all(Pred, []) -> true. + +any(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> true; + false -> any(Pred, Tail) + end; +any(Pred, []) -> false. + +map(F, List) -> [ F(E) || E <- List ]. + +flatmap(F, [Hd|Tail]) -> + F(Hd) ++ flatmap(F, Tail); +flatmap(F, []) -> []. + +foldl(F, Accu, [Hd|Tail]) -> + foldl(F, F(Hd, Accu), Tail); +foldl(F, Accu, []) -> Accu. + +foldr(F, Accu, [Hd|Tail]) -> + F(Hd, foldr(F, Accu, Tail)); +foldr(F, Accu, []) -> Accu. + +filter(Pred, List) -> [ E || E <- List, Pred(E) ]. + +zf(F, [Hd|Tail]) -> + case F(Hd) of + true -> + [Hd|zf(F, Tail)]; + {true,Val} -> + [Val|zf(F, Tail)]; + false -> + zf(F, Tail) + end; +zf(F, []) -> []. + +foreach(F, [Hd|Tail]) -> + F(Hd), + foreach(F, Tail); +foreach(F, []) -> ok. + +mapfoldl(F, Accu0, [Hd|Tail]) -> + {R,Accu1} = F(Hd, Accu0), + {Rs,Accu2} = mapfoldl(F, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl(F, Accu, []) -> {[],Accu}. + +mapfoldr(F, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr(F, Accu0, Tail), + {R,Accu2} = F(Hd, Accu1), + {[R|Rs],Accu2}; +mapfoldr(F, Accu, []) -> {[],Accu}. + +takewhile(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> [Hd|takewhile(Pred, Tail)]; + false -> [] + end; +takewhile(Pred, []) -> []. + +dropwhile(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> dropwhile(Pred, Tail); + false -> [Hd|Tail] + end; +dropwhile(Pred, []) -> []. + +splitwith(Pred, List) -> splitwith(Pred, List, []). + +splitwith(Pred, [Hd|Tail], Taken) -> + case Pred(Hd) of + true -> splitwith(Pred, Tail, [Hd|Taken]); + false -> {reverse(Taken), [Hd|Tail]} + end; +splitwith(Pred, [], Taken) -> {reverse(Taken),[]}. + +%% Versions of the above functions with extra arguments. + +all(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> all(Pred, Eas, Tail); + false -> false + end; +all(Pred, Eas, []) -> true. + +any(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> true; + false -> any(Pred, Eas, Tail) + end; +any(Pred, Eas, []) -> false. + +map(F, Eas, List) -> [ apply(F, [E|Eas]) || E <- List ]. + +flatmap(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]) ++ flatmap(F, Eas, Tail); +flatmap(F, Eas, []) -> []. + +foldl(F, Eas, Accu, [Hd|Tail]) -> + foldl(F, Eas, apply(F, [Hd,Accu|Eas]), Tail); +foldl(F, Eas, Accu, []) -> Accu. + +foldr(F, Eas, Accu, [Hd|Tail]) -> + apply(F, [Hd,foldr(F, Eas, Accu, Tail)|Eas]); +foldr(F, Eas, Accu, []) -> + Accu. + +filter(Pred, Eas, List) -> [ E || E <- List, apply(Pred, [E|Eas]) ]. + +zf(F, Eas, [Hd|Tail]) -> + case apply(F, [Hd|Eas]) of + true -> + [Hd|zf(F, Eas, Tail)]; + {true,Val} -> + [Val|zf(F, Eas, Tail)]; + false -> + zf(F, Eas, Tail) + end; +zf(F, Eas, []) -> []. + +foreach(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]), + foreach(F, Eas, Tail); +foreach(F, Eas, []) -> ok. + +mapfoldl(F, Eas, Accu0, [Hd|Tail]) -> + {R,Accu1} = apply(F, [Hd,Accu0|Eas]), + {Rs,Accu2} = mapfoldl(F, Eas, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl(F, Eas, Accu, []) -> {[],Accu}. + +mapfoldr(F, Eas, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr(F, Eas, Accu0, Tail), + {R,Accu2} = apply(F, [Hd,Accu1|Eas]), + {[R|Rs],Accu2}; +mapfoldr(F, Eas, Accu, []) -> {[],Accu}. + +%% takewhile/2, dropwhile/2 and splitwith/2 do not have versions with +%% extra arguments as this going to be discontinued. + + + + + +%%% +++++++++++++++++++++++++++++++++++++++ +%%% +%%% Same as above but with "_1" added to the function names +%%% + + +%% member_1(X, L) -> (true | false) +%% test if X is a member of the list L + +%member_1(X, [X|_]) -> true; +%member_1(X, [_|Y]) -> +% member_1(X, Y); +%member_1(X, []) -> false. + +member_1(X, L) when list(L) -> + case erlang:member_1(X, L) of + L1 when list(L1) -> + receive after 1 -> ok end, + member_1(X, L1); + Boolean -> + Boolean + end. + +%% append_1(X, Y) appends lists X and Y + +append_1(L1, L2) -> L1 ++ L2. + +%% append_1(L) appends the list of lists L + +append_1([E]) -> E; +append_1([H|T]) -> H ++ append_1(T); +append_1([]) -> []. + +%% subtract_1(List1, List2) subtract elements in List2 form List1. + +subtract_1(L1, L2) -> L1 -- L2. + +%% reverse_1(L) reverse all elements in the list L + +reverse_1(X) -> reverse_1(X, []). + +%reverse_1([H|T], Y) -> +% reverse_1(T, [H|Y]); +%reverse_1([], X) -> X. + +reverse_1(List0, Result0) when list(List0) -> + case erlang:reverse_1(List0, Result0) of + {List, Result} -> + receive after 1 -> ok end, + reverse_1(List, Result); + Result -> + Result + end. + + +%% nth_1(N, L) returns the N`th element of the list L +%% nthtail_1(N, L) returns the N`th tail of the list L + +nth_1(1, [H|T]) -> H; +nth_1(N, [_|T]) when N > 1 -> + nth_1(N - 1, T). + +nthtail_1(1, [H|T]) -> T; +nthtail_1(N, [H|T]) when N > 1 -> + nthtail_1(N - 1, T); +nthtail_1(0, L) when list(L) -> L. + +%% prefix_1(Prefix, List) -> (true | false) + +prefix_1([X|PreTail], [X|Tail]) -> + prefix_1(PreTail, Tail); +prefix_1([], List) -> true; +prefix_1(_,_) -> false. + + +%% suffix_1(Suffix, List) -> (true | false) + +suffix_1(Suffix, Suffix) -> true; +suffix_1(Suffix, [_|Tail]) -> + suffix_1(Suffix, Tail); +suffix_1(Suffix, []) -> false. + +%% last(List) returns the last element in a list. + +last_1([E]) -> E; +last_1([E|Es]) -> + last_1(Es). + +%% seq(Min, Max) -> [Min,Min+1, ..., Max] +%% seq(Min, Max, Incr) -> [Min,Min+Incr, ..., Max] +%% returns the sequence Min..Max +%% Min <= Max and Min and Max must be integers + +seq_1(Min, Max) when integer(Min), integer(Max), Min =< Max -> + seq_1(Min, Max, 1, []). + +seq_1(Min, Max, Incr) -> + seq_1(Min, Min + ((Max-Min) div Incr) * Incr, Incr, []). + +seq_1(Min, Min, I, L) -> [Min|L]; +seq_1(Min, Max, I, L) -> seq_1(Min, Max-I, I, [Max|L]). + +%% sum(L) suns the sum of the elements in L + +sum_1(L) -> sum_1(L, 0). +sum_1([H|T], Sum) -> sum_1(T, Sum + H); +sum_1([], Sum) -> Sum. + +%% duplicate(N, X) -> [X,X,X,.....,X] (N times) +%% return N copies of X + +duplicate_1(N, X) when integer(N), N >= 0 -> duplicate_1(N, X, []). + +duplicate_1(0, _, L) -> L; +duplicate_1(N, X, L) -> duplicate_1(N-1, X, [X|L]). + + +%% min(L) -> returns the minimum element of the list L + +min_1([H|T]) -> min_1(T, H). + +min_1([H|T], Min) when H < Min -> min_1(T, H); +min_1([_|T], Min) -> min_1(T, Min); +min_1([], Min) -> Min. + +%% max(L) -> returns the maximum element of the list L + +max_1([H|T]) -> max_1(T, H). + +max_1([H|T], Max) when H > Max -> max_1(T, H); +max_1([_|T], Max) -> max_1(T, Max); +max_1([], Max) -> Max. + +%% sublist(List, Start, Length) +%% Returns the sub-list starting at Start of length Length. + +sublist_1(List, S, L) when L >= 0 -> + sublist_1(nthtail_1(S-1, List), L). + +sublist_1([H|T], L) when L > 0 -> + [H|sublist_1(T, L-1)]; +sublist_1(List, L) -> []. + +%% delete(Item, List) -> List' +%% Delete the first occurance of Item from the list L. + +delete_1(Item, [Item|Rest]) -> Rest; +delete_1(Item, [H|Rest]) -> + [H|delete_1(Item, Rest)]; +delete_1(Item, []) -> []. + +%% sort(L) -> sorts the list L + +sort_1([X]) -> [X]; +sort_1([]) -> []; +sort_1(X) -> split_and_sort_1(X, [], []). + +split_and_sort_1([A,B|T], X, Y) -> + split_and_sort_1(T, [A|X], [B|Y]); +split_and_sort_1([H], X, Y) -> + split_and_sort_1([], [H|X], Y); +split_and_sort_1([], X, Y) -> + merge_1(sort_1(X), sort_1(Y), []). + +%% merge(X, Y) -> L +%% merges two sorted lists X and Y + +merge_1(X, Y) -> merge_1(X, Y, []). + +merge_1([H1|T1], [H2|T2], L) when H1 < H2 -> + merge_1(T1, [H2|T2], [H1|L]); +merge_1(T1, [H2|T2], L) -> + merge_1(T1, T2, [H2|L]); +merge_1([H|T], T2, L) -> + merge_1(T, T2, [H|L]); +merge_1([], [], L) -> + reverse_1(L). + +%% concat(L) concatinate the list representation of the elements +%% in L - the elements in L can be atoms, integers of strings. +%% Returns a list of characters. + +concat_1(List) -> + flatmap_1(fun thing_to_list/1, List). + +thing_to_list_1(X) when integer(X) -> integer_to_list(X); +thing_to_list_1(X) when float(X) -> float_to_list(X); +thing_to_list_1(X) when atom(X) -> atom_to_list(X); +thing_to_list_1(X) when list(X) -> X. %Assumed to be a string + +%% flatten(List) +%% flatten(List, Tail) +%% Flatten a list, adding optional tail. + +flatten_1(List) -> + flatten_1(List, [], []). + +flatten_1(List, Tail) -> + flatten_1(List, [], Tail). + +flatten_1([H|T], Cont, Tail) when list(H) -> + flatten_1(H, [T|Cont], Tail); +flatten_1([H|T], Cont, Tail) -> + [H|flatten_1(T, Cont, Tail)]; +flatten_1([], [H|Cont], Tail) -> + flatten_1(H, Cont, Tail); +flatten_1([], [], Tail) -> + Tail. + +%% flat_length(List) (undocumented can be rmove later) +%% Calculate the length of a list of lists. + +flat_length_1(List) -> flatlength_1(List). + +%% flatlength(List) +%% Calculate the length of a list of lists. + +flatlength_1(List) -> + flatlength_1(List, 0). + +flatlength_1([H|T], L) when list(H) -> + flatlength_1(H, flatlength_1(T, L)); +flatlength_1([H|T], L) -> + flatlength_1(T, L + 1); +flatlength_1([], L) -> L. + +%% keymember(Key, Index, [Tuple]) +%% keysearch(Key, Index, [Tuple]) +%% keydelete(Key, Index, [Tuple]) +%% keyreplace(Key, Index, [Tuple], NewTuple) +%% keysort(Index, [Tuple]) +%% keymerge(Index, [Tuple], [Tuple]) +%% keymap(Function, Index, [Tuple]) +%% keymap(Function, ExtraArgs, Index, [Tuple]) + +keymember_1(Key, N, [T|Ts]) when element(N, T) == Key -> true; +keymember_1(Key, N, [T|Ts]) -> + keymember_1(Key, N, Ts); +keymember_1(Key, N, []) -> false. + +keysearch_1(Key, N, [H|T]) when element(N, H) == Key -> + {value, H}; +keysearch_1(Key, N, [H|T]) -> + keysearch_1(Key, N, T); +keysearch_1(Key, N, []) -> false. + +keydelete_1(Key, N, [H|T]) when element(N, H) == Key -> T; +keydelete_1(Key, N, [H|T]) -> + [H|keydelete_1(Key, N, T)]; +keydelete_1(Key, N, []) -> []. + +keyreplace_1(Key, Pos, [Tup|Tail], New) when element(Pos, Tup) == Key -> + [New|Tail]; +keyreplace_1(Key, Pos, [H|T], New) -> + [H|keyreplace_1(Key, Pos, T, New)]; +keyreplace_1(Key, Pos, [], New) -> []. + +keysort_1(Index, [X]) -> [X]; +keysort_1(Index, []) -> []; +keysort_1(Index, X) -> split_and_keysort_1(X, [], [], Index). + +split_and_keysort_1([A,B|T], X, Y, Index) -> + split_and_keysort_1(T, [A|X], [B|Y], Index); +split_and_keysort_1([H], X, Y, Index) -> + split_and_keysort_1([], [H|X], Y, Index); +split_and_keysort_1([], X, Y, Index) -> + keymerge_1(Index, keysort_1(Index, X), keysort_1(Index, Y), []). + +keymerge_1(Index, X, Y) -> keymerge_1(Index, X, Y, []). + +keymerge_1(I, [H1|T1], [H2|T2], L) when element(I, H1) < element(I, H2) -> + keymerge_1(I, T1, [H2|T2], [H1|L]); +keymerge_1(Index, T1, [H2|T2], L) -> + keymerge_1(Index,T1, T2, [H2|L]); +keymerge_1(Index,[H|T], T2, L) -> + keymerge_1(Index,T, T2, [H|L]); +keymerge_1(Index, [], [], L) -> + reverse_1(L). + +keymap_1(Fun, Index, [Tup|Tail]) -> + [setelement(Index, Tup, Fun(element(Index, Tup)))|keymap_1(Fun, Index, Tail)]; +keymap_1( _, _ , []) -> []. + +keymap_1(Fun, ExtraArgs, Index, [Tup|Tail]) -> + [setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))| + keymap_1(Fun, ExtraArgs, Index, Tail)]; +keymap_1( _, _ , _, []) -> []. + +%% all(Predicate, List) +%% any(Predicate, List) +%% map(Function, List) +%% flatmap(Function, List) +%% foldl(Function, First, List) +%% foldr(Function, Last, List) +%% filter(Predicate, List) +%% zf(Function, List) +%% mapfoldl(Function, First, List) +%% mapfoldr(Function, Last, List) +%% foreach(Function, List) +%% takewhile(Predicate, List) +%% dropwhile(Predicate, List) +%% splitwith(Predicate, List) +%% for list programming. Function here is either a 'fun' or a tuple +%% {Module,Name} and we use apply/2 to evaluate. The name zf is a joke! +%% +%% N.B. Unless where the functions actually needs it only foreach/2/3, +%% which is meant to be used for its side effects, has a defined order +%% of evaluation. +%% +%% There are also versions with an extra argument, ExtraArgs, which is a +%% list of extra arguments to each call. + +all_1(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> all_1(Pred, Tail); + false -> false + end; +all_1(Pred, []) -> true. + +any_1(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> true; + false -> any_1(Pred, Tail) + end; +any_1(Pred, []) -> false. + +map_1(F, List) -> [ F(E) || E <- List ]. + +flatmap_1(F, [Hd|Tail]) -> + F(Hd) ++ flatmap_1(F, Tail); +flatmap_1(F, []) -> []. + +foldl_1(F, Accu, [Hd|Tail]) -> + foldl_1(F, F(Hd, Accu), Tail); +foldl_1(F, Accu, []) -> Accu. + +foldr_1(F, Accu, [Hd|Tail]) -> + F(Hd, foldr_1(F, Accu, Tail)); +foldr_1(F, Accu, []) -> Accu. + +filter_1(Pred, List) -> [ E || E <- List, Pred(E) ]. + +zF(F, [Hd|Tail]) -> + case F(Hd) of + true -> + [Hd|zF(F, Tail)]; + {true,Val} -> + [Val|zF(F, Tail)]; + false -> + zF(F, Tail) + end; +zF(F, []) -> []. + +foreach_1(F, [Hd|Tail]) -> + F(Hd), + foreach_1(F, Tail); +foreach_1(F, []) -> ok. + +mapfoldl_1(F, Accu0, [Hd|Tail]) -> + {R,Accu1} = F(Hd, Accu0), + {Rs,Accu2} = mapfoldl_1(F, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl_1(F, Accu, []) -> {[],Accu}. + +mapfoldr_1(F, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr_1(F, Accu0, Tail), + {R,Accu2} = F(Hd, Accu1), + {[R|Rs],Accu2}; +mapfoldr_1(F, Accu, []) -> {[],Accu}. + +takewhile_1(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> [Hd|takewhile_1(Pred, Tail)]; + false -> [] + end; +takewhile_1(Pred, []) -> []. + +dropwhile_1(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> dropwhile_1(Pred, Tail); + false -> [Hd|Tail] + end; +dropwhile_1(Pred, []) -> []. + +splitwith_1(Pred, List) -> splitwith_1(Pred, List, []). + +splitwith_1(Pred, [Hd|Tail], Taken) -> + case Pred(Hd) of + true -> splitwith_1(Pred, Tail, [Hd|Taken]); + false -> {reverse_1(Taken), [Hd|Tail]} + end; +splitwith_1(Pred, [], Taken) -> {reverse_1(Taken),[]}. + +%% Versions of the above functions with extra arguments. + +all_1(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> all_1(Pred, Eas, Tail); + false -> false + end; +all_1(Pred, Eas, []) -> true. + +any_1(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> true; + false -> any_1(Pred, Eas, Tail) + end; +any_1(Pred, Eas, []) -> false. + +map_1(F, Eas, List) -> [ apply(F, [E|Eas]) || E <- List ]. + +flatmap_1(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]) ++ flatmap_1(F, Eas, Tail); +flatmap_1(F, Eas, []) -> []. + +foldl_1(F, Eas, Accu, [Hd|Tail]) -> + foldl_1(F, Eas, apply(F, [Hd,Accu|Eas]), Tail); +foldl_1(F, Eas, Accu, []) -> Accu. + +foldr_1(F, Eas, Accu, [Hd|Tail]) -> + apply(F, [Hd,foldr_1(F, Eas, Accu, Tail)|Eas]); +foldr_1(F, Eas, Accu, []) -> + Accu. + +filter_1(Pred, Eas, List) -> [ E || E <- List, apply(Pred, [E|Eas]) ]. + +zF(F, Eas, [Hd|Tail]) -> + case apply(F, [Hd|Eas]) of + true -> + [Hd|zF(F, Eas, Tail)]; + {true,Val} -> + [Val|zF(F, Eas, Tail)]; + false -> + zF(F, Eas, Tail) + end; +zF(F, Eas, []) -> []. + +foreach_1(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]), + foreach_1(F, Eas, Tail); +foreach_1(F, Eas, []) -> ok. + +mapfoldl_1(F, Eas, Accu0, [Hd|Tail]) -> + {R,Accu1} = apply(F, [Hd,Accu0|Eas]), + {Rs,Accu2} = mapfoldl_1(F, Eas, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl_1(F, Eas, Accu, []) -> {[],Accu}. + +mapfoldr_1(F, Eas, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr_1(F, Eas, Accu0, Tail), + {R,Accu2} = apply(F, [Hd,Accu1|Eas]), + {[R|Rs],Accu2}; +mapfoldr_1(F, Eas, Accu, []) -> {[],Accu}. + +%% takewhile/2, dropwhile/2 and splitwith/2 do not have versions with +%% extra arguments as this going to be discontinued. + + + + + + +%%% +++++++++++++++++++++ +%%% +%%% "_2" + + + + + +%% member_2(X, L) -> _2(true | false) +%% test if X is a member of the list L + +%member_2(X, [X|_]) -> true; +%member_2(X, [_|Y]) -> +% member_2(X, Y); +%member_2(X, []) -> false. + +member_2(X, L) when list(L) -> + case erlang:member_2(X, L) of + L1 when list(L1) -> + receive after 1 -> ok end, + member_2(X, L1); + Boolean -> + Boolean + end. + +%% append_2(X, Y) appends lists X and Y + +append_2(L1, L2) -> L1 ++ L2. + +%% append_2(L) appends the list of lists L + +append_2([E]) -> E; +append_2([H|T]) -> H ++ append_2(T); +append_2([]) -> []. + +%% subtract_2(List1, List2) subtract elements in List2 form List1. + +subtract_2(L1, L2) -> L1 -- L2. + +%% reverse_2(L) reverse all elements in the list L + +reverse_2(X) -> reverse_2(X, []). + +%reverse_2([H|T], Y) -> +% reverse_2(T, [H|Y]); +%reverse_2([], X) -> X. + +reverse_2(List0, Result0) when list(List0) -> + case erlang:reverse_2(List0, Result0) of + {List, Result} -> + receive after 1 -> ok end, + reverse_2(List, Result); + Result -> + Result + end. + + +%% nth_2(N, L) returns the N`th element of the list L +%% nthtail_2(N, L) returns the N`th tail of the list L + +nth_2(1, [H|T]) -> H; +nth_2(N, [_|T]) when N > 1 -> + nth_2(N - 1, T). + +nthtail_2(1, [H|T]) -> T; +nthtail_2(N, [H|T]) when N > 1 -> + nthtail_2(N - 1, T); +nthtail_2(0, L) when list(L) -> L. + +%% prefix_2(Prefix, List) -> _2(true | false) + +prefix_2([X|PreTail], [X|Tail]) -> + prefix_2(PreTail, Tail); +prefix_2([], List) -> true; +prefix_2(_,_) -> false. + + +%% suffix_2(Suffix, List) -> _2(true | false) + +suffix_2(Suffix, Suffix) -> true; +suffix_2(Suffix, [_|Tail]) -> + suffix_2(Suffix, Tail); +suffix_2(Suffix, []) -> false. + +%% last_2(List) returns the last element in a list. + +last_2([E]) -> E; +last_2([E|Es]) -> + last_2(Es). + +%% seq_2(Min, Max) -> [Min,Min+1, ..., Max] +%% seq_2(Min, Max, Incr) -> [Min,Min+Incr, ..., Max] +%% returns the sequence Min..Max +%% Min <= Max and Min and Max must be integers + +seq_2(Min, Max) when integer(Min), integer(Max), Min =< Max -> + seq_2(Min, Max, 1, []). + +seq_2(Min, Max, Incr) -> + seq_2(Min, Min + ((Max-Min) div Incr) * Incr, Incr, []). + +seq_2(Min, Min, I, L) -> [Min|L]; +seq_2(Min, Max, I, L) -> seq_2(Min, Max-I, I, [Max|L]). + +%% sum_2(L) suns the sum of the elements in L + +sum_2(L) -> sum_2(L, 0). +sum_2([H|T], Sum) -> sum_2(T, Sum + H); +sum_2([], Sum) -> Sum. + +%% duplicate_2(N, X) -> [X,X,X,.....,X] _2(N times) +%% return N copies of X + +duplicate_2(N, X) when integer(N), N >= 0 -> duplicate_2(N, X, []). + +duplicate_2(0, _, L) -> L; +duplicate_2(N, X, L) -> duplicate_2(N-1, X, [X|L]). + + +%% min_2(L) -> returns the minimum element of the list L + +min_2([H|T]) -> min_2(T, H). + +min_2([H|T], Min) when H < Min -> min_2(T, H); +min_2([_|T], Min) -> min_2(T, Min); +min_2([], Min) -> Min. + +%% max_2(L) -> returns the maximum element of the list L + +max_2([H|T]) -> max_2(T, H). + +max_2([H|T], Max) when H > Max -> max_2(T, H); +max_2([_|T], Max) -> max_2(T, Max); +max_2([], Max) -> Max. + +%% sublist(List, Start, Length) +%% Returns the sub-list starting at Start of length Length. + +sublist_2(List, S, L) when L >= 0 -> + sublist_2(nthtail_2(S-1, List), L). + +sublist_2([H|T], L) when L > 0 -> + [H|sublist_2(T, L-1)]; +sublist_2(List, L) -> []. + +%% delete_2(Item, List) -> List' +%% Delete the first occurance of Item from the list L. + +delete_2(Item, [Item|Rest]) -> Rest; +delete_2(Item, [H|Rest]) -> + [H|delete_2(Item, Rest)]; +delete_2(Item, []) -> []. + +%% sort_2(L) -> sorts the list L + +sort_2([X]) -> [X]; +sort_2([]) -> []; +sort_2(X) -> split_and_sort_2(X, [], []). + +split_and_sort_2([A,B|T], X, Y) -> + split_and_sort_2(T, [A|X], [B|Y]); +split_and_sort_2([H], X, Y) -> + split_and_sort_2([], [H|X], Y); +split_and_sort_2([], X, Y) -> + merge_2(sort_2(X), sort_2(Y), []). + +%% merge_2(X, Y) -> L +%% merges two sorted lists X and Y + +merge_2(X, Y) -> merge_2(X, Y, []). + +merge_2([H1|T1], [H2|T2], L) when H1 < H2 -> + merge_2(T1, [H2|T2], [H1|L]); +merge_2(T1, [H2|T2], L) -> + merge_2(T1, T2, [H2|L]); +merge_2([H|T], T2, L) -> + merge_2(T, T2, [H|L]); +merge_2([], [], L) -> + reverse_2(L). + +%% concat_2(L) concatinate the list representation of the elements +%% in L - the elements in L can be atoms, integers of strings. +%% Returns a list of characters. + +concat_2(List) -> + flatmap_2(fun thing_to_list/1, List). + +thing_to_list_2(X) when integer(X) -> integer_to_list(X); +thing_to_list_2(X) when float(X) -> float_to_list(X); +thing_to_list_2(X) when atom(X) -> atom_to_list(X); +thing_to_list_2(X) when list(X) -> X. %Assumed to be a string + +%% flatten_2(List) +%% flatten_2(List, Tail) +%% Flatten a list, adding optional tail. + +flatten_2(List) -> + flatten_2(List, [], []). + +flatten_2(List, Tail) -> + flatten_2(List, [], Tail). + +flatten_2([H|T], Cont, Tail) when list(H) -> + flatten_2(H, [T|Cont], Tail); +flatten_2([H|T], Cont, Tail) -> + [H|flatten_2(T, Cont, Tail)]; +flatten_2([], [H|Cont], Tail) -> + flatten_2(H, Cont, Tail); +flatten_2([], [], Tail) -> + Tail. + +%% flat_length_2(List) _2(undocumented can be rmove later) +%% Calculate the length of a list of lists. + +flat_length_2(List) -> flatlength_2(List). + +%% flatlength_2(List) +%% Calculate the length of a list of lists. + +flatlength_2(List) -> + flatlength_2(List, 0). + +flatlength_2([H|T], L) when list(H) -> + flatlength_2(H, flatlength_2(T, L)); +flatlength_2([H|T], L) -> + flatlength_2(T, L + 1); +flatlength_2([], L) -> L. + +%% keymember_2(Key, Index, [Tuple]) +%% keysearch_2(Key, Index, [Tuple]) +%% keydelete_2(Key, Index, [Tuple]) +%% keyreplace_2(Key, Index, [Tuple], NewTuple) +%% keysort_2(Index, [Tuple]) +%% keymerge_2(Index, [Tuple], [Tuple]) +%% keymap_2(Function, Index, [Tuple]) +%% keymap_2(Function, ExtraArgs, Index, [Tuple]) + +keymember_2(Key, N, [T|Ts]) when element(N, T) == Key -> true; +keymember_2(Key, N, [T|Ts]) -> + keymember_2(Key, N, Ts); +keymember_2(Key, N, []) -> false. + +keysearch_2(Key, N, [H|T]) when element(N, H) == Key -> + {value, H}; +keysearch_2(Key, N, [H|T]) -> + keysearch_2(Key, N, T); +keysearch_2(Key, N, []) -> false. + +keydelete_2(Key, N, [H|T]) when element(N, H) == Key -> T; +keydelete_2(Key, N, [H|T]) -> + [H|keydelete_2(Key, N, T)]; +keydelete_2(Key, N, []) -> []. + +keyreplace_2(Key, Pos, [Tup|Tail], New) when element(Pos, Tup) == Key -> + [New|Tail]; +keyreplace_2(Key, Pos, [H|T], New) -> + [H|keyreplace_2(Key, Pos, T, New)]; +keyreplace_2(Key, Pos, [], New) -> []. + +keysort_2(Index, [X]) -> [X]; +keysort_2(Index, []) -> []; +keysort_2(Index, X) -> split_and_keysort_2(X, [], [], Index). + +split_and_keysort_2([A,B|T], X, Y, Index) -> + split_and_keysort_2(T, [A|X], [B|Y], Index); +split_and_keysort_2([H], X, Y, Index) -> + split_and_keysort_2([], [H|X], Y, Index); +split_and_keysort_2([], X, Y, Index) -> + keymerge_2(Index, keysort_2(Index, X), keysort_2(Index, Y), []). + +keymerge_2(Index, X, Y) -> keymerge_2(Index, X, Y, []). + +keymerge_2(I, [H1|T1], [H2|T2], L) when element(I, H1) < element(I, H2) -> + keymerge_2(I, T1, [H2|T2], [H1|L]); +keymerge_2(Index, T1, [H2|T2], L) -> + keymerge_2(Index,T1, T2, [H2|L]); +keymerge_2(Index,[H|T], T2, L) -> + keymerge_2(Index,T, T2, [H|L]); +keymerge_2(Index, [], [], L) -> + reverse_2(L). + +keymap_2(Fun, Index, [Tup|Tail]) -> + [setelement(Index, Tup, Fun(element(Index, Tup)))|keymap_2(Fun, Index, Tail)]; +keymap_2( _, _ , []) -> []. + +keymap_2(Fun, ExtraArgs, Index, [Tup|Tail]) -> + [setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))| + keymap_2(Fun, ExtraArgs, Index, Tail)]; +keymap_2( _, _ , _, []) -> []. + +%% all_2(Predicate, List) +%% any_2(Predicate, List) +%% map_2(Function, List) +%% flatmap_2(Function, List) +%% foldl_2(Function, First, List) +%% foldr_2(Function, Last, List) +%% filter_2(Predicate, List) +%% zF(Function, List) +%% mapfoldl_2(Function, First, List) +%% mapfoldr_2(Function, Last, List) +%% foreach_2(Function, List) +%% takewhile_2(Predicate, List) +%% dropwhile_2(Predicate, List) +%% splitwith_2(Predicate, List) +%% for list programming. Function here is either a 'fun' or a tuple +%% {Module,Name} and we use apply/2 to evaluate. The name zf is a joke! +%% +%% N.B. Unless where the functions actually needs it only foreach/2/3, +%% which is meant to be used for its side effects, has a defined order +%% of evaluation. +%% +%% There are also versions with an extra argument, ExtraArgs, which is a +%% list of extra arguments to each call. + +all_2(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> all_2(Pred, Tail); + false -> false + end; +all_2(Pred, []) -> true. + +any_2(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> true; + false -> any_2(Pred, Tail) + end; +any_2(Pred, []) -> false. + +map_2(F, List) -> [ F(E) || E <- List ]. + +flatmap_2(F, [Hd|Tail]) -> + F(Hd) ++ flatmap_2(F, Tail); +flatmap_2(F, []) -> []. + +foldl_2(F, Accu, [Hd|Tail]) -> + foldl_2(F, F(Hd, Accu), Tail); +foldl_2(F, Accu, []) -> Accu. + +foldr_2(F, Accu, [Hd|Tail]) -> + F(Hd, foldr_2(F, Accu, Tail)); +foldr_2(F, Accu, []) -> Accu. + +filter_2(Pred, List) -> [ E || E <- List, Pred(E) ]. + +zF_2(F, [Hd|Tail]) -> + case F(Hd) of + true -> + [Hd|zF_2(F, Tail)]; + {true,Val} -> + [Val|zF_2(F, Tail)]; + false -> + zF_2(F, Tail) + end; +zF_2(F, []) -> []. + +foreach_2(F, [Hd|Tail]) -> + F(Hd), + foreach_2(F, Tail); +foreach_2(F, []) -> ok. + +mapfoldl_2(F, Accu0, [Hd|Tail]) -> + {R,Accu1} = F(Hd, Accu0), + {Rs,Accu2} = mapfoldl_2(F, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl_2(F, Accu, []) -> {[],Accu}. + +mapfoldr_2(F, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr_2(F, Accu0, Tail), + {R,Accu2} = F(Hd, Accu1), + {[R|Rs],Accu2}; +mapfoldr_2(F, Accu, []) -> {[],Accu}. + +takewhile_2(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> [Hd|takewhile_2(Pred, Tail)]; + false -> [] + end; +takewhile_2(Pred, []) -> []. + +dropwhile_2(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> dropwhile_2(Pred, Tail); + false -> [Hd|Tail] + end; +dropwhile_2(Pred, []) -> []. + +splitwith_2(Pred, List) -> splitwith_2(Pred, List, []). + +splitwith_2(Pred, [Hd|Tail], Taken) -> + case Pred(Hd) of + true -> splitwith_2(Pred, Tail, [Hd|Taken]); + false -> {reverse_2(Taken), [Hd|Tail]} + end; +splitwith_2(Pred, [], Taken) -> {reverse_2(Taken),[]}. + +%% Versions of the above functions with extra arguments. + +all_2(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> all_2(Pred, Eas, Tail); + false -> false + end; +all_2(Pred, Eas, []) -> true. + +any_2(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> true; + false -> any_2(Pred, Eas, Tail) + end; +any_2(Pred, Eas, []) -> false. + +map_2(F, Eas, List) -> [ apply(F, [E|Eas]) || E <- List ]. + +flatmap_2(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]) ++ flatmap_2(F, Eas, Tail); +flatmap_2(F, Eas, []) -> []. + +foldl_2(F, Eas, Accu, [Hd|Tail]) -> + foldl_2(F, Eas, apply(F, [Hd,Accu|Eas]), Tail); +foldl_2(F, Eas, Accu, []) -> Accu. + +foldr_2(F, Eas, Accu, [Hd|Tail]) -> + apply(F, [Hd,foldr_2(F, Eas, Accu, Tail)|Eas]); +foldr_2(F, Eas, Accu, []) -> + Accu. + +filter_2(Pred, Eas, List) -> [ E || E <- List, apply(Pred, [E|Eas]) ]. + +zF_2(F, Eas, [Hd|Tail]) -> + case apply(F, [Hd|Eas]) of + true -> + [Hd|zF_2(F, Eas, Tail)]; + {true,Val} -> + [Val|zF_2(F, Eas, Tail)]; + false -> + zF_2(F, Eas, Tail) + end; +zF_2(F, Eas, []) -> []. + +foreach_2(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]), + foreach_2(F, Eas, Tail); +foreach_2(F, Eas, []) -> ok. + +mapfoldl_2(F, Eas, Accu0, [Hd|Tail]) -> + {R,Accu1} = apply(F, [Hd,Accu0|Eas]), + {Rs,Accu2} = mapfoldl_2(F, Eas, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl_2(F, Eas, Accu, []) -> {[],Accu}. + +mapfoldr_2(F, Eas, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr_2(F, Eas, Accu0, Tail), + {R,Accu2} = apply(F, [Hd,Accu1|Eas]), + {[R|Rs],Accu2}; +mapfoldr_2(F, Eas, Accu, []) -> {[],Accu}. + +%% takewhile/2, dropwhile/2 and splitwith/2 do not have versions with +%% extra arguments as this going to be discontinued. + + + + + +%%% +++++++++++++++++++ +%%% +%%% With "_3" + + + + +%% member_3(X, L) -> _3(true | false) +%% test if X is a member of the list L + +%member_3(X, [X|_]) -> true; +%member_3(X, [_|Y]) -> +% member_3(X, Y); +%member_3(X, []) -> false. + +member_3(X, L) when list(L) -> + case erlang:member(X, L) of + L1 when list(L1) -> + receive after 1 -> ok end, + member_3(X, L1); + Boolean -> + Boolean + end. + +%% append_3(X, Y) appends lists X and Y + +append_3(L1, L2) -> L1 ++ L2. + +%% append_3(L) appends the list of lists L + +append_3([E]) -> E; +append_3([H|T]) -> H ++ append_3(T); +append_3([]) -> []. + +%% subtract_3(List1, List2) subtract elements in List2 form List1. + +subtract_3(L1, L2) -> L1 -- L2. + +%% reverse_3(L) reverse all elements in the list L + +reverse_3(X) -> reverse_3(X, []). + +%reverse_3([H|T], Y) -> +% reverse_3(T, [H|Y]); +%reverse_3([], X) -> X. + +reverse_3(List0, Result0) when list(List0) -> + case erlang:reverse_3(List0, Result0) of + {List, Result} -> + receive after 1 -> ok end, + reverse_3(List, Result); + Result -> + Result + end. + + +%% nth_3(N, L) returns the N`th element of the list L +%% nthtail_3(N, L) returns the N`th tail of the list L + +nth_3(1, [H|T]) -> H; +nth_3(N, [_|T]) when N > 1 -> + nth_3(N - 1, T). + +nthtail_3(1, [H|T]) -> T; +nthtail_3(N, [H|T]) when N > 1 -> + nthtail_3(N - 1, T); +nthtail_3(0, L) when list(L) -> L. + +%% prefix_3(Prefix, List) -> _3(true | false) + +prefix_3([X|PreTail], [X|Tail]) -> + prefix_3(PreTail, Tail); +prefix_3([], List) -> true; +prefix_3(_,_) -> false. + + +%% suffix_3(Suffix, List) -> _3(true | false) + +suffix_3(Suffix, Suffix) -> true; +suffix_3(Suffix, [_|Tail]) -> + suffix_3(Suffix, Tail); +suffix_3(Suffix, []) -> false. + +%% last_3(List) returns the last element in a list. + +last_3([E]) -> E; +last_3([E|Es]) -> + last_3(Es). + +%% seq_3(Min, Max) -> [Min,Min+1, ..., Max] +%% seq_3(Min, Max, Incr) -> [Min,Min+Incr, ..., Max] +%% returns the sequence Min..Max +%% Min <= Max and Min and Max must be integers + +seq_3(Min, Max) when integer(Min), integer(Max), Min =< Max -> + seq_3(Min, Max, 1, []). + +seq_3(Min, Max, Incr) -> + seq_3(Min, Min + ((Max-Min) div Incr) * Incr, Incr, []). + +seq_3(Min, Min, I, L) -> [Min|L]; +seq_3(Min, Max, I, L) -> seq_3(Min, Max-I, I, [Max|L]). + +%% sum_3(L) suns the sum of the elements in L + +sum_3(L) -> sum_3(L, 0). +sum_3([H|T], Sum) -> sum_3(T, Sum + H); +sum_3([], Sum) -> Sum. + +%% duplicate_3(N, X) -> [X,X,X,.....,X] _3(N times) +%% return N copies of X + +duplicate_3(N, X) when integer(N), N >= 0 -> duplicate_3(N, X, []). + +duplicate_3(0, _, L) -> L; +duplicate_3(N, X, L) -> duplicate_3(N-1, X, [X|L]). + + +%% min_3(L) -> returns the minimum element of the list L + +min_3([H|T]) -> min_3(T, H). + +min_3([H|T], Min) when H < Min -> min_3(T, H); +min_3([_|T], Min) -> min_3(T, Min); +min_3([], Min) -> Min. + +%% max_3(L) -> returns the maximum element of the list L + +max_3([H|T]) -> max_3(T, H). + +max_3([H|T], Max) when H > Max -> max_3(T, H); +max_3([_|T], Max) -> max_3(T, Max); +max_3([], Max) -> Max. + +%% sublist_3(List, Start, Length) +%% Returns the sub-list starting at Start of length Length. + +sublist_3(List, S, L) when L >= 0 -> + sublist_3(nthtail_3(S-1, List), L). + +sublist_3([H|T], L) when L > 0 -> + [H|sublist_3(T, L-1)]; +sublist_3(List, L) -> []. + +%% delete_3(Item, List) -> List' +%% Delete the first occurance of Item from the list L. + +delete_3(Item, [Item|Rest]) -> Rest; +delete_3(Item, [H|Rest]) -> + [H|delete_3(Item, Rest)]; +delete_3(Item, []) -> []. + +%% sort_3(L) -> sorts the list L + +sort_3([X]) -> [X]; +sort_3([]) -> []; +sort_3(X) -> split_and_sort_3(X, [], []). + +split_and_sort_3([A,B|T], X, Y) -> + split_and_sort_3(T, [A|X], [B|Y]); +split_and_sort_3([H], X, Y) -> + split_and_sort_3([], [H|X], Y); +split_and_sort_3([], X, Y) -> + merge_3(sort_3(X), sort_3(Y), []). + +%% merge_3(X, Y) -> L +%% merges two sorted lists X and Y + +merge_3(X, Y) -> merge_3(X, Y, []). + +merge_3([H1|T1], [H2|T2], L) when H1 < H2 -> + merge_3(T1, [H2|T2], [H1|L]); +merge_3(T1, [H2|T2], L) -> + merge_3(T1, T2, [H2|L]); +merge_3([H|T], T2, L) -> + merge_3(T, T2, [H|L]); +merge_3([], [], L) -> + reverse_3(L). + +%% concat_3(L) concatinate the list representation of the elements +%% in L - the elements in L can be atoms, integers of strings. +%% Returns a list of characters. + +concat_3(List) -> + flatmap_3(fun thing_to_list/1, List). + +thing_to_list_3(X) when integer(X) -> integer_to_list(X); +thing_to_list_3(X) when float(X) -> float_to_list(X); +thing_to_list_3(X) when atom(X) -> atom_to_list(X); +thing_to_list_3(X) when list(X) -> X. %Assumed to be a string + +%% flatten_3(List) +%% flatten_3(List, Tail) +%% Flatten a list, adding optional tail. + +flatten_3(List) -> + flatten_3(List, [], []). + +flatten_3(List, Tail) -> + flatten_3(List, [], Tail). + +flatten_3([H|T], Cont, Tail) when list(H) -> + flatten_3(H, [T|Cont], Tail); +flatten_3([H|T], Cont, Tail) -> + [H|flatten_3(T, Cont, Tail)]; +flatten_3([], [H|Cont], Tail) -> + flatten_3(H, Cont, Tail); +flatten_3([], [], Tail) -> + Tail. + +%% flat_length_3(List) _3(undocumented can be rmove later) +%% Calculate the length of a list of lists. + +flat_length_3(List) -> flatlength_3(List). + +%% flatlength_3(List) +%% Calculate the length of a list of lists. + +flatlength_3(List) -> + flatlength_3(List, 0). + +flatlength_3([H|T], L) when list(H) -> + flatlength_3(H, flatlength_3(T, L)); +flatlength_3([H|T], L) -> + flatlength_3(T, L + 1); +flatlength_3([], L) -> L. + +%% keymember_3(Key, Index, [Tuple]) +%% keysearch_3(Key, Index, [Tuple]) +%% keydelete_3(Key, Index, [Tuple]) +%% keyreplace_3(Key, Index, [Tuple], NewTuple) +%% keysort_3(Index, [Tuple]) +%% keymerge_3(Index, [Tuple], [Tuple]) +%% keymap_3(Function, Index, [Tuple]) +%% keymap_3(Function, ExtraArgs, Index, [Tuple]) + +keymember_3(Key, N, [T|Ts]) when element(N, T) == Key -> true; +keymember_3(Key, N, [T|Ts]) -> + keymember_3(Key, N, Ts); +keymember_3(Key, N, []) -> false. + +keysearch_3(Key, N, [H|T]) when element(N, H) == Key -> + {value, H}; +keysearch_3(Key, N, [H|T]) -> + keysearch_3(Key, N, T); +keysearch_3(Key, N, []) -> false. + +keydelete_3(Key, N, [H|T]) when element(N, H) == Key -> T; +keydelete_3(Key, N, [H|T]) -> + [H|keydelete_3(Key, N, T)]; +keydelete_3(Key, N, []) -> []. + +keyreplace_3(Key, Pos, [Tup|Tail], New) when element(Pos, Tup) == Key -> + [New|Tail]; +keyreplace_3(Key, Pos, [H|T], New) -> + [H|keyreplace_3(Key, Pos, T, New)]; +keyreplace_3(Key, Pos, [], New) -> []. + +keysort_3(Index, [X]) -> [X]; +keysort_3(Index, []) -> []; +keysort_3(Index, X) -> split_and_keysort_3(X, [], [], Index). + +split_and_keysort_3([A,B|T], X, Y, Index) -> + split_and_keysort_3(T, [A|X], [B|Y], Index); +split_and_keysort_3([H], X, Y, Index) -> + split_and_keysort_3([], [H|X], Y, Index); +split_and_keysort_3([], X, Y, Index) -> + keymerge_3(Index, keysort_3(Index, X), keysort_3(Index, Y), []). + +keymerge_3(Index, X, Y) -> keymerge_3(Index, X, Y, []). + +keymerge_3(I, [H1|T1], [H2|T2], L) when element(I, H1) < element(I, H2) -> + keymerge_3(I, T1, [H2|T2], [H1|L]); +keymerge_3(Index, T1, [H2|T2], L) -> + keymerge_3(Index,T1, T2, [H2|L]); +keymerge_3(Index,[H|T], T2, L) -> + keymerge_3(Index,T, T2, [H|L]); +keymerge_3(Index, [], [], L) -> + reverse_3(L). + +keymap_3(Fun, Index, [Tup|Tail]) -> + [setelement(Index, Tup, Fun(element(Index, Tup)))|keymap_3(Fun, Index, Tail)]; +keymap_3( _, _ , []) -> []. + +keymap_3(Fun, ExtraArgs, Index, [Tup|Tail]) -> + [setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))| + keymap_3(Fun, ExtraArgs, Index, Tail)]; +keymap_3( _, _ , _, []) -> []. + +%% all_3(Predicate, List) +%% any_3(Predicate, List) +%% map_3(Function, List) +%% flatmap_3(Function, List) +%% foldl_3(Function, First, List) +%% foldr_3(Function, Last, List) +%% filter_3(Predicate, List) +%% zF(Function, List) +%% mapfoldl_3(Function, First, List) +%% mapfoldr_3(Function, Last, List) +%% foreach_3(Function, List) +%% takewhile_3(Predicate, List) +%% dropwhile_3(Predicate, List) +%% splitwith_3(Predicate, List) +%% for list programming. Function here is either a 'fun' or a tuple +%% {Module,Name} and we use apply/2 to evaluate. The name zf is a joke! +%% +%% N.B. Unless where the functions actually needs it only foreach/2/3, +%% which is meant to be used for its side effects, has a defined order +%% of evaluation. +%% +%% There are also versions with an extra argument, ExtraArgs, which is a +%% list of extra arguments to each call. + +all_3(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> all_3(Pred, Tail); + false -> false + end; +all_3(Pred, []) -> true. + +any_3(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> true; + false -> any_3(Pred, Tail) + end; +any_3(Pred, []) -> false. + +map_3(F, List) -> [ F(E) || E <- List ]. + +flatmap_3(F, [Hd|Tail]) -> + F(Hd) ++ flatmap_3(F, Tail); +flatmap_3(F, []) -> []. + +foldl_3(F, Accu, [Hd|Tail]) -> + foldl_3(F, F(Hd, Accu), Tail); +foldl_3(F, Accu, []) -> Accu. + +foldr_3(F, Accu, [Hd|Tail]) -> + F(Hd, foldr_3(F, Accu, Tail)); +foldr_3(F, Accu, []) -> Accu. + +filter_3(Pred, List) -> [ E || E <- List, Pred(E) ]. + +zF_3(F, [Hd|Tail]) -> + case F(Hd) of + true -> + [Hd|zF_3(F, Tail)]; + {true,Val} -> + [Val|zF_3(F, Tail)]; + false -> + zF_3(F, Tail) + end; +zF_3(F, []) -> []. + +foreach_3(F, [Hd|Tail]) -> + F(Hd), + foreach_3(F, Tail); +foreach_3(F, []) -> ok. + +mapfoldl_3(F, Accu0, [Hd|Tail]) -> + {R,Accu1} = F(Hd, Accu0), + {Rs,Accu2} = mapfoldl_3(F, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl_3(F, Accu, []) -> {[],Accu}. + +mapfoldr_3(F, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr_3(F, Accu0, Tail), + {R,Accu2} = F(Hd, Accu1), + {[R|Rs],Accu2}; +mapfoldr_3(F, Accu, []) -> {[],Accu}. + +takewhile_3(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> [Hd|takewhile_3(Pred, Tail)]; + false -> [] + end; +takewhile_3(Pred, []) -> []. + +dropwhile_3(Pred, [Hd|Tail]) -> + case Pred(Hd) of + true -> dropwhile_3(Pred, Tail); + false -> [Hd|Tail] + end; +dropwhile_3(Pred, []) -> []. + +splitwith_3(Pred, List) -> splitwith_3(Pred, List, []). + +splitwith_3(Pred, [Hd|Tail], Taken) -> + case Pred(Hd) of + true -> splitwith_3(Pred, Tail, [Hd|Taken]); + false -> {reverse_3(Taken), [Hd|Tail]} + end; +splitwith_3(Pred, [], Taken) -> {reverse_3(Taken),[]}. + +%% Versions of the above functions with extra arguments. + +all_3(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> all_3(Pred, Eas, Tail); + false -> false + end; +all_3(Pred, Eas, []) -> true. + +any_3(Pred, Eas, [Hd|Tail]) -> + case apply(Pred, [Hd|Eas]) of + true -> true; + false -> any_3(Pred, Eas, Tail) + end; +any_3(Pred, Eas, []) -> false. + +map_3(F, Eas, List) -> [ apply(F, [E|Eas]) || E <- List ]. + +flatmap_3(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]) ++ flatmap_3(F, Eas, Tail); +flatmap_3(F, Eas, []) -> []. + +foldl_3(F, Eas, Accu, [Hd|Tail]) -> + foldl_3(F, Eas, apply(F, [Hd,Accu|Eas]), Tail); +foldl_3(F, Eas, Accu, []) -> Accu. + +foldr_3(F, Eas, Accu, [Hd|Tail]) -> + apply(F, [Hd,foldr_3(F, Eas, Accu, Tail)|Eas]); +foldr_3(F, Eas, Accu, []) -> + Accu. + +filter_3(Pred, Eas, List) -> [ E || E <- List, apply(Pred, [E|Eas]) ]. + +zF_3(F, Eas, [Hd|Tail]) -> + case apply(F, [Hd|Eas]) of + true -> + [Hd|zF(F, Eas, Tail)]; + {true,Val} -> + [Val|zF(F, Eas, Tail)]; + false -> + zF(F, Eas, Tail) + end; +zF_3(F, Eas, []) -> []. + +foreach_3(F, Eas, [Hd|Tail]) -> + apply(F, [Hd|Eas]), + foreach_3(F, Eas, Tail); +foreach_3(F, Eas, []) -> ok. + +mapfoldl_3(F, Eas, Accu0, [Hd|Tail]) -> + {R,Accu1} = apply(F, [Hd,Accu0|Eas]), + {Rs,Accu2} = mapfoldl_3(F, Eas, Accu1, Tail), + {[R|Rs],Accu2}; +mapfoldl_3(F, Eas, Accu, []) -> {[],Accu}. + +mapfoldr_3(F, Eas, Accu0, [Hd|Tail]) -> + {Rs,Accu1} = mapfoldr_3(F, Eas, Accu0, Tail), + {R,Accu2} = apply(F, [Hd,Accu1|Eas]), + {[R|Rs],Accu2}; +mapfoldr_3(F, Eas, Accu, []) -> {[],Accu}. + +%% takewhile/2, dropwhile/2 and splitwith/2 do not have versions with +%% extra arguments as this going to be discontinued. + + + + +lots_of_atoms () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms1 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms2 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms3 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms4 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms5 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms6 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms7 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms8 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms9 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms10 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms11 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. + + +lots_of_atoms12 () -> + +Aa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Af = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ag = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ah = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aba = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aca = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ada = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aea = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aga = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aha = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aab = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahb = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aac = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aec = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahc = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aad = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Add = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aed = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahd = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aae = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ace = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ade = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aee = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Age = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahe = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + + +Aaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + + +Aaaaaa= 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahaaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aabaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aebaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahbaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aacaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Accaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aecaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahcaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aadaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Acdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Addaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aedaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Agdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ahdaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aaeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Abeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aceaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Adeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aeeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Afeaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Ageaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg', + +Aheaaa = 'rnevgoirnvire iriej iirejgierjg ioegjrigj oiegj oijetig oijtgej oj oiejg iojetijwokfopkewmf irjgo ergjerifjiugnuignuit euhg uieuignuiergnuienrgueringiun uiegniuerngui iugne uegniuetgniuetgnuientg unegngiuethgiueugnieg'. diff --git a/lib/debugger/test/int_SUITE_data/ordsets1.erl b/lib/debugger/test/int_SUITE_data/ordsets1.erl new file mode 100644 index 0000000000..a01d35eb51 --- /dev/null +++ b/lib/debugger/test/int_SUITE_data/ordsets1.erl @@ -0,0 +1,191 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Copyright (C) 1991, Ellemtel Telecommunications Systems Laboratories +%% File : ordsets.erl +%% Author : Robert Virding +%% Purpose : Functions for manipulating sets as ordered lists. + +%% As yet some of these are not very efficiently written. + +-module(ordsets1). + +-export([new_set/0,is_set/1,set_to_list/1,list_to_set/1]). +-export([is_element/2,add_element/2,del_element/2]). +-export([union/2,union/1,intersection/2,intersection/1]). +-export([subtract/2,subset/2]). + +%% new_set() +%% Return a new empty ordered set. + +new_set() -> + []. + +%% is_set(Set) +%% Return 'true' if Set is an ordered set of elements, else 'false'. + +is_set([E|Es]) -> + is_set(Es, E); +is_set([]) -> + true. + +is_set([E2|Es], E1) when E1 < E2 -> + is_set(Es, E2); +is_set([E2|Es], E1) -> + false; +is_set([], E1) -> + true. + +%% set_to_list(OrdSet) +%% Return the elements in OrdSet as a list. + +set_to_list(S) -> + S. + +%% list_to_set(List) +%% Build an ordered set from the elements in List. + +list_to_set([E|Es]) -> + add_element(E, list_to_set(Es)); +list_to_set([]) -> + []. + +%% is_element(Element, OrdSet) +%% Return 'true' if Element is an element of OrdSet, else 'false'. + +is_element(E, [H|Es]) when E < H -> + false; +is_element(E, [H|Es]) when E == H -> + true; +is_element(E, [H|Es]) when E > H -> + is_element(E, Es); +is_element(E, []) -> + false. + +%% add_element(Element, OrdSet) +%% Return OrdSet with Element inserted in it. + +add_element(E, [H|Es]) when E < H -> + [E,H|Es]; +add_element(E, [H|Es]) when E == H -> + [H|Es]; +add_element(E, [H|Es]) when E > H -> + [H|add_element(E, Es)]; +add_element(E, []) -> + [E]. + +%% del_element(Element, OrdSet) +%% Return OrdSet but with Element removed. + +del_element(E, [H|Es]) when E < H -> + [H|Es]; +del_element(E, [H|Es]) when E == H -> + Es; +del_element(E, [H|Es]) when E > H -> + [H|del_element(E, Es)]; +del_element(E, []) -> + []. + +%% union(Set1, Set2) +%% Return the union of Set1 and Set2. + +union([H1|Es1], [H2|Es2]) when H1 < H2 -> + [H1|union(Es1, [H2|Es2])]; +union([H1|Es1], [H2|Es2]) when H1 == H2 -> + [H1|union(Es1, Es2)]; +union([H1|Es1], [H2|Es2]) when H1 > H2 -> + [H2|union([H1|Es1], Es2)]; +union([], Es2) -> + Es2; +union(Es1, []) -> + Es1. + +%% union(OrdSets) +%% Return the union of the list of sets. + +union([S1,S2|Ss]) -> + union1(union(S1,S2), Ss); +union([S]) -> + S; +union([]) -> + []. + +union1(S1, [S2|Ss]) -> + union1(union(S1, S2), Ss); +union1(S1, []) -> + S1. + +%% intersection(Set1, Set2) +%% Return the intersection of Set1 and Set2. + +intersection([H1|Es1], [H2|Es2]) when H1 < H2 -> + intersection(Es1, [H2|Es2]); +intersection([H1|Es1], [H2|Es2]) when H1 == H2 -> + [H1|intersection(Es1, Es2)]; +intersection([H1|Es1], [H2|Es2]) when H1 > H2 -> + intersection([H1|Es1], Es2); +intersection([], Es2) -> + []; +intersection(Es1, []) -> + []. + +%% intersection(OrdSets) +%% Return the intersection of the list of sets. + +intersection([S1,S2|Ss]) -> + intersection1(intersection(S1,S2), Ss); +intersection([S]) -> + S; +intersection([]) -> + []. + +intersection1(S1, [S2|Ss]) -> + intersection1(intersection(S1, S2), Ss); +intersection1(S1, []) -> + S1. + +%% subtract(Set1, Set2) +%% Return all and only the elements of Set1 which are not also in Set2. + +subtract([H1|Es1], [H2|Es2]) when H1 < H2 -> + [H1|subtract(Es1, [H2|Es2])]; +subtract([H1|Es1], [H2|Es2]) when H1 == H2 -> + subtract(Es1, Es2); +subtract([H1|Es1], [H2|Es2]) when H1 > H2 -> + subtract([H1|Es1], Es2); +subtract([], Es2) -> + []; +subtract(Es1, []) -> + Es1. + +%% subset(Set1, Set2) +%% Return 'true' when every element of Set1 is also a member of Set2, +%% else 'false'. + +subset([H1|Es1], [H2|Es2]) when H1 < H2 -> %H1 not in Set2 + false; +subset([H1|Es1], [H2|Es2]) when H1 == H2 -> + subset(Es1, Es2); +subset([H1|Es1], [H2|Es2]) when H1 > H2 -> + subset([H1|Es1], Es2); +subset([], Es2) -> + true; +subset(Es1, []) -> + false. diff --git a/lib/debugger/test/int_SUITE_data/test.erl b/lib/debugger/test/int_SUITE_data/test.erl new file mode 100644 index 0000000000..679b266380 --- /dev/null +++ b/lib/debugger/test/int_SUITE_data/test.erl @@ -0,0 +1,152 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(test). + +%%-compile(export_all). +-export([test1/0, + test2/0, + test3/0, + test4/0, + test5/0, + test6/1, + test7/0, + test8/1, + test9/0, + test10/0, + test11/0 + ]). + + +-export([test9_server/1]). + + +test1() -> + R1 = lists1:reverse("retep"), + R2 = ordsets1:list_to_set([b,c,a,2,4,1]), + R3 = lists1:reverse("nilo"), + {R1,R2, R3}. + +test2() -> + R1 = spawn(lists1,reverse,["retep"]), + R2 = spawn(ordsets1,list_to_set,[[b,c,a,2,4,1]]), + R3 = spawn(lists1,reverse,["nilo"]), + {R1,R2, R3}. + + +test3() -> + A = a, + Pid = spawn(?MODULE, test1,[]), + B = b, + {A, B, Pid}. + +test4() -> + Pid = spawn(?MODULE, test1,[]), + A = a, + B = b, + {A, B, Pid}. +test5() -> + L1 = [a,b,c], + L = length(L1), + A = a, + B = b, + {A, B, L, L1}. + + + +test6(0) -> + ok; +test6(N) when N>0 -> + spawn(lists1,reverse,["adolfiparisrorsirapifloda"]), + test6(N-1). + + +test7() -> + CurDirReturn = file:get_cwd(), + {ok, CurDir} = CurDirReturn, + DirListReturn = file:list_dir(CurDir), + {ok, DirList} = DirListReturn, + io:format("~w~n",[DirList]). + + +test8(List) -> + %% foo + %%bar + %% foo + %%bar + %% foo + %%bar + %% foo + %%bar + + L2 = [gamma|List], + {L2, List}. + +test9() -> + S1 = spawn(?MODULE, test9_server,[self()]), + S2 = spawn(?MODULE, test9_server,[bongo]), + S3 = spawn(?MODULE, test9_server,[42]), + + test9_loop(S1,S2,S3). + +test9_loop(S1,S2,S3) -> + receive + {S1, hej} -> + io:format("S1 ~n"), + test9_loop(S1,S2,S3); + {S2, hej} -> + io:format("S2 ~n"), + test9_loop(S1,S2,S3); + {S3, hej} -> + io:format("S3 ~n"), + test9_loop(S1,S2,S3) + end. + + +test9_server(Pid) -> + io:format("started server: ~p~n",[Pid]), + test9_server1(Pid). + +test9_server1(Pid) -> + Pad = {pad, Pid}, + test9_server2(Pad). + +test9_server2(Pad) -> + {pad, Pid} = Pad, + Pid ! {self(), hej}. + + + + + +test10() -> + receive + X -> + done + after 20000 -> + timeout + end. + +test11() -> + receive + X -> + done + end. diff --git a/lib/debugger/test/int_SUITE_data/test1.erl b/lib/debugger/test/int_SUITE_data/test1.erl new file mode 100644 index 0000000000..a93416cbac --- /dev/null +++ b/lib/debugger/test/int_SUITE_data/test1.erl @@ -0,0 +1,34 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(test1). + +-compile(export_all). + + +foo() -> + A = [1,2,3], + B = [a,b,c], + C = [d,e,f], + D = my_lists:append(A,B), + E = my_lists:append(D,C), + F = [1], + G = my_lists:append(E,F), + {A,B,C,D,E,F,G}. diff --git a/lib/debugger/test/int_break_SUITE.erl b/lib/debugger/test/int_break_SUITE.erl new file mode 100644 index 0000000000..b7b3c5598a --- /dev/null +++ b/lib/debugger/test/int_break_SUITE.erl @@ -0,0 +1,92 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(int_break_SUITE). + +%% Test break points. + +-include("test_server.hrl"). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2, + basic/1,cleanup/1]). + +-export([auto_attach/1]). + +all(suite) -> + [basic,cleanup]. + +init_per_testcase(_Case, Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line Mod = ordsets1, + ?line {module,Mod} = int:i(filename:join(DataDir, Mod)), + ?line ok = io:format("Interpreted modules: ~p", [int:interpreted()]), + ?line Dog = test_server:timetrap(?t:minutes(0.5)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + ?line ok = io:format("Interpreted modules: ~p", [int:interpreted()]), + ?line Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +basic(doc) -> "Tests setting a few break points."; +basic(suite) -> []; +basic(Config) when list(Config) -> + ?line int:auto_attach([init], {?MODULE,auto_attach}), + ?line S1 = [] = ordsets1:new_set(), + ?line ok = i:ib(ordsets1, 86), + ?line S2 = [xxx] = ordsets1:add_element(xxx, S1), + ?line S3 = [xxx,y] = ordsets1:add_element(y, S2), + ?line ok = i:ib(ordsets1, union, 2), + ?line [xxx,y,z] = ordsets1:union(S3, [z]), + ok. + +cleanup(doc) -> "Make sure that the auto-attach flag is turned off."; +cleanup(suite) -> []; +cleanup(Config) when list(Config) -> + ?line int:auto_attach(false), + ok. + +auto_attach(Pid) -> + {ok, Meta} = int:attached(Pid), + io:format("Pid = ~p; Meta = ~p", [Pid,Meta]), + link(Meta), + attach_loop(Pid, Meta). + +attach_loop(Pid, Meta) -> + receive + Msg -> + io:format("attached: ~p", [Msg]), + attach_cmd(Msg, Pid, Meta), + attach_loop(Pid, Meta) + end. + +attach_cmd({Meta,{break_at,ordsets1,36,2}}, _Pid, Meta) -> + int:meta(Meta, continue); +attach_cmd({Meta,{break_at,ordsets1,87,_}}, _Pid, Meta) -> + int:meta(Meta, continue); +attach_cmd({Meta,{break_at,ordsets1,89,_}}, _Pid, Meta) -> + int:meta(Meta, continue); +attach_cmd({Meta,{break_at,ordsets1,Line,_}}, _Pid, Meta) when 107 =< Line, Line =< 115 -> + int:meta(Meta, finish); +attach_cmd({Meta,{break_at,_Mod,_Line,_Other}}=Cmd, _Pid, Meta) -> + io:format("attached: no action for ~p", [Cmd]); +attach_cmd(_, _Pid, _Meta) -> + ok. diff --git a/lib/debugger/test/int_break_SUITE_data/Makefile.src b/lib/debugger/test/int_break_SUITE_data/Makefile.src new file mode 100644 index 0000000000..0d1ee35a67 --- /dev/null +++ b/lib/debugger/test/int_break_SUITE_data/Makefile.src @@ -0,0 +1,25 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +EFLAGS=+debug_info + +all: ordsets1.@EMULATOR@ + +ordsets1.@EMULATOR@: ordsets1.erl + erlc $(EFLAGS) ordsets1.erl diff --git a/lib/debugger/test/int_break_SUITE_data/ordsets1.erl b/lib/debugger/test/int_break_SUITE_data/ordsets1.erl new file mode 100644 index 0000000000..6300c6097c --- /dev/null +++ b/lib/debugger/test/int_break_SUITE_data/ordsets1.erl @@ -0,0 +1,188 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Purpose : Functions for manipulating sets as ordered lists. + +%% As yet some of these are not very efficiently written. + +-module(ordsets1). + +-export([new_set/0,is_set/1,set_to_list/1,list_to_set/1]). +-export([is_element/2,add_element/2,del_element/2]). +-export([union/2,union/1,intersection/2,intersection/1]). +-export([subtract/2,subset/2]). + +%% new_set() +%% Return a new empty ordered set. + +new_set() -> + []. + +%% is_set(Set) +%% Return 'true' if Set is an ordered set of elements, else 'false'. + +is_set([E|Es]) -> + is_set(Es, E); +is_set([]) -> + true. + +is_set([E2|Es], E1) when E1 < E2 -> + is_set(Es, E2); +is_set([E2|Es], E1) -> + false; +is_set([], E1) -> + true. + +%% set_to_list(OrdSet) +%% Return the elements in OrdSet as a list. + +set_to_list(S) -> + S. + +%% list_to_set(List) +%% Build an ordered set from the elements in List. + +list_to_set([E|Es]) -> + add_element(E, list_to_set(Es)); +list_to_set([]) -> + []. + +%% is_element(Element, OrdSet) +%% Return 'true' if Element is an element of OrdSet, else 'false'. + +is_element(E, [H|Es]) when E < H -> + false; +is_element(E, [H|Es]) when E == H -> + true; +is_element(E, [H|Es]) when E > H -> + is_element(E, Es); +is_element(E, []) -> + false. + +%% add_element(Element, OrdSet) +%% Return OrdSet with Element inserted in it. + +add_element(E, [H|_]=Es) when E < H -> + [E|Es]; +add_element(E, [H|_]=Es) when E == H -> + Es; +add_element(E, [H|Es]) when E > H -> + [H|add_element(E, Es)]; +add_element(E, []) -> + [E]. + +%% del_element(Element, OrdSet) +%% Return OrdSet but with Element removed. + +del_element(E, [H|_]=Es) when E < H -> + Es; +del_element(E, [H|Es]) when E == H -> + Es; +del_element(E, [H|Es]) when E > H -> + [H|del_element(E, Es)]; +del_element(E, []) -> + []. + +%% union(Set1, Set2) +%% Return the union of Set1 and Set2. + +union([H1|Es1], [H2|_]=Es2) when H1 < H2 -> + [H1|union(Es1, Es2)]; +union([H1|Es1], [H2|Es2]) when H1 == H2 -> + [H1|union(Es1, Es2)]; +union([H1|_]=Es1, [H2|Es2]) when H1 > H2 -> + [H2|union(Es1, Es2)]; +union([], Es2) -> + Es2; +union(Es1, []) -> + Es1. + +%% union(OrdSets) +%% Return the union of the list of sets. + +union([S1,S2|Ss]) -> + union1(union(S1,S2), Ss); +union([S]) -> + S; +union([]) -> + []. + +union1(S1, [S2|Ss]) -> + union1(union(S1, S2), Ss); +union1(S1, []) -> + S1. + +%% intersection(Set1, Set2) +%% Return the intersection of Set1 and Set2. + +intersection([H1|Es1], [H2|_]=Es2) when H1 < H2 -> + intersection(Es1, Es2); +intersection([H1|Es1], [H2|Es2]) when H1 == H2 -> + [H1|intersection(Es1, Es2)]; +intersection([H1|_]=Es1, [H2|Es2]) when H1 > H2 -> + intersection(Es1, Es2); +intersection([], Es2) -> + []; +intersection(Es1, []) -> + []. + +%% intersection(OrdSets) +%% Return the intersection of the list of sets. + +intersection([S1,S2|Ss]) -> + intersection1(intersection(S1,S2), Ss); +intersection([S]) -> + S; +intersection([]) -> + []. + +intersection1(S1, [S2|Ss]) -> + intersection1(intersection(S1, S2), Ss); +intersection1(S1, []) -> + S1. + +%% subtract(Set1, Set2) +%% Return all and only the elements of Set1 which are not also in Set2. + +subtract([H1|Es1], [H2|_]=Es2) when H1 < H2 -> + [H1|subtract(Es1, Es2)]; +subtract([H1|Es1], [H2|Es2]) when H1 == H2 -> + subtract(Es1, Es2); +subtract([H1|_]=Es1, [H2|Es2]) when H1 > H2 -> + subtract(Es1, Es2); +subtract([], Es2) -> + []; +subtract(Es1, []) -> + Es1. + +%% subset(Set1, Set2) +%% Return 'true' when every element of Set1 is also a member of Set2, +%% else 'false'. + +subset([H1|Es1], [H2|Es2]) when H1 < H2 -> %H1 not in Set2 + false; +subset([H1|Es1], [H2|Es2]) when H1 == H2 -> + subset(Es1, Es2); +subset([H1|Es1], [H2|Es2]) when H1 > H2 -> + subset([H1|Es1], Es2); +subset([], Es2) -> + true; +subset(Es1, []) -> + false. diff --git a/lib/debugger/test/int_eval_SUITE.erl b/lib/debugger/test/int_eval_SUITE.erl new file mode 100644 index 0000000000..19b006e750 --- /dev/null +++ b/lib/debugger/test/int_eval_SUITE.erl @@ -0,0 +1,277 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(int_eval_SUITE). + +%% Purpose: Deeper test of the evaluator. + +-export([all/1,init_per_testcase/2, fin_per_testcase/2, + bifs_outside_erlang/1, spawning/1, applying/1, + catch_and_throw/1, external_call/1, test_module_info/1, + apply_interpreted_fun/1, apply_uninterpreted_fun/1, + interpreted_exit/1, otp_8310/1]). + +%% Helpers. +-export([applier/3]). + +-define(IM, my_int_eval_module). + +-include("test_server.hrl"). + +all(suite) -> + [bifs_outside_erlang,spawning,applying,catch_and_throw, + external_call,test_module_info, + apply_interpreted_fun,apply_uninterpreted_fun, + interpreted_exit, otp_8310]. + +init_per_testcase(_Case, Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {module,?IM} = int:i(filename:join(DataDir, ?IM)), + ?line ok = io:format("Interpreted modules: ~p",[int:interpreted()]), + {ok, Dog} = timer:apply_after(timer:minutes(1), + erlang, exit, [self(), kill]), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + ok = io:format("Interpreted modules: ~p", [int:interpreted()]), + Dog = ?config(watchdog, Config), + timer:cancel(Dog), + ok. + +bifs_outside_erlang(doc) -> + "Test that BIFs outside the erlang module are correctly evaluated."; +bifs_outside_erlang(suite) -> + []; +bifs_outside_erlang(Config) when is_list(Config) -> + Fun = fun() -> + Id = ?IM:ets_new(), + Self = self(), + ok = io:format("Self: ~p", [Self]), + Info = ets:info(Id), + {owner,Self} = lists:nth(2, Info), + %% Was + %% {owner,Self} = element(2, Info), + %% in R10B. + ?IM:ets_delete(Id), + ok + end, + ?line ok = spawn_eval(Fun), + ok. + +spawning(doc) -> + "Try evalutate spawn_link/3."; +spawning(suite) -> + []; +spawning(Config) when is_list(Config) -> + ?line ok = spawn_eval(fun() -> ?IM:spawn_test() end). + +applying(doc) -> + "Try various sorts of applies."; +applying(suite) -> + []; +applying(Config) when is_list(Config) -> + Fun = fun({number,X}, {number,Y}) -> X+Y end, + ?line ok = spawn_eval(fun() -> ?IM:apply_test(Fun) end). + +catch_and_throw(doc) -> + "Test catch and throw/1."; +catch_and_throw(suite) -> + []; +catch_and_throw(Config) when is_list(Config) -> + {a,ball} = spawn_eval(fun() -> ok = ?IM:catch_a_ball(), + catch ?IM:throw_a_ball() end), + + %% Throw and catch without any extra outer catch. + + ?line process_flag(trap_exit, true), + ?line Pid1 = spawn_link(fun() -> exit(?IM:catch_a_ball()) end), + receive + {'EXIT',Pid1,ok} -> ok; + {'EXIT',Pid1,Bad1} -> ?line ?t:fail({bad_message,Bad1}) + after 5000 -> + ?line ?t:fail(timeout) + end, + + + %% Throw without catch. + + ?line Pid2 = spawn_link(fun() -> ?IM:throw_a_ball() end), + receive + {'EXIT',Pid2,{{nocatch,{a,ball}},[_|_]}} -> ok; + {'EXIT',Pid2,Bad2} -> ?line ?t:fail({bad_message,Bad2}) + after 5000 -> + ?line ?t:fail(timeout) + end, + + ?line ok = ?IM:more_catch(fun(_) -> ?IM:exit_me() end), + ?line ok = ?IM:more_catch(fun(_) -> exit({unint, exit}) end), + ?line {a, ball} = ?IM:more_catch(fun(_) -> ?IM:throw_a_ball() end), + ?line {b, ball} = ?IM:more_catch(fun(_) -> throw({b,ball}) end), + + ExitInt = {'EXIT',{int,exit}}, + ExitU = {'EXIT',{unint,exit}}, + + ?line ExitInt = (catch ?IM:more_nocatch(fun(_) -> ?IM:exit_me() end)), + ?line ExitU = (catch ?IM:more_nocatch(fun(_) -> exit({unint, exit}) end)), + ?line {a, ball} = (catch {error, ?IM:more_nocatch(fun(_) -> ?IM:throw_a_ball() end)}), + ?line {b, ball} = (catch {error, ?IM:more_nocatch(fun(_) -> throw({b,ball}) end)}), + ok. + +external_call(doc) -> + "Test external calls."; +external_call(suite) -> + []; +external_call(Config) when is_list(Config) -> + ?line ok = spawn_eval(fun() -> ?IM:external_call_test({some,stupid,data}) end). + +test_module_info(doc) -> + "Test the module_info/0,1 functions."; +test_module_info(suite) -> + []; +test_module_info(Config) when is_list(Config) -> + ?line ModInfo = ?IM:module_info(), + ?line {value,{exports,Exp}} = lists:keysearch(exports, 1, ModInfo), + ?line {value,{attributes,Attr}} = lists:keysearch(attributes, 1, ModInfo), + ?line Exp = ?IM:module_info(exports), + ?line Attr = ?IM:module_info(attributes), + ?line {value,{stupid_attribute,[{a,b}]}} = + lists:keysearch(stupid_attribute, 1, Attr), + + %% Check exports using a list comprehension in the module itself. + + ?line ok = ?IM:check_exports(Exp), + + %% Call module_info/0,1 from the module itself. + + ?line ok = ?IM:check_module_info(ModInfo, Exp), + + ok. + +apply_interpreted_fun(doc) -> + "Apply a fun defined in interpreted code."; +apply_interpreted_fun(suite) -> []; +apply_interpreted_fun(Config) when is_list(Config) -> + + %% Called from uninterpreted code + ?line F1 = spawn_eval(fun() -> ?IM:give_me_a_fun_0() end), + ?line perfectly_alright = spawn_eval(fun() -> F1() end), + ?line ATerm = {a,term}, + ?line F2 = spawn_eval(fun() -> ?IM:give_me_a_fun_0(ATerm) end), + ?line {ok,ATerm} = spawn_eval(fun() -> F2() end), + + %% Called from uninterpreted code, badarity + ?line {'EXIT',{{badarity,{F1,[snape]}},[{?MODULE,_,_}|_]}} = + spawn_eval(fun() -> F1(snape) end), + + %% Called from uninterpreted code, error in fun + ?line F3 = spawn_eval(fun() -> ?IM:give_me_a_bad_fun() end), + ?line {'EXIT',{snape,[{?IM,_FunName,_}|_]}} = + spawn_eval(fun() -> F3(snape) end), + + %% Called from within interpreted code + ?line perfectly_alright = spawn_eval(fun() -> ?IM:do_apply(F1) end), + + %% Called from within interpreted code, badarity + ?line {'EXIT',{{badarity,{F1,[snape]}},[{?IM,do_apply,_}|_]}} = + spawn_eval(fun() -> ?IM:do_apply(F1, snape) end), + + %% Called from within interpreted code, error in fun + ?line {'EXIT',{snape,[{?IM,_FunName,_}|_]}} = + spawn_eval(fun() -> ?IM:do_apply(F3, snape) end), + + %% Try some more complex funs. + ?line F4 = ?IM:give_me_a_fun_1(14, 42), + ?line {false,yes,yeah,false} = + F4({{1,nope},{14,yes},{42,yeah},{100,forget_it}}), + ?line [this_is_ok,me_too] = + F4([{-24,no_way},{15,this_is_ok},{1333,forget_me},{37,me_too}]), + + %% OTP-5837 + %% Try fun with guard containing variable bound in environment + ?line [yes,no,no,no] = ?IM:otp_5837(1), + + ok. + +apply_uninterpreted_fun(doc) -> + "Apply a fun defined outside interpreted code."; +apply_uninterpreted_fun(suite) -> []; +apply_uninterpreted_fun(Config) when is_list(Config) -> + + ?line F1 = fun(snape) -> + erlang:error(snape); + (_Arg) -> + perfectly_alright + end, + + %% Ok + ?line perfectly_alright = + spawn_eval(fun() -> ?IM:do_apply(F1, any_arg) end), + + %% Badarity (evaluated in dbg_debugged, which calls erlang:apply/2) + ?line {'EXIT',{{badarity,{F1,[]}},[{erlang,apply,_}|_]}} = + spawn_eval(fun() -> ?IM:do_apply(F1) end), + + %% Error in fun + ?line {'EXIT',{snape,[{?MODULE,_FunName,_}|_]}} = + spawn_eval(fun() -> ?IM:do_apply(F1, snape) end), + + ok. + +%% +%% Try executing an interpreted exit/1 call. +%% + +interpreted_exit(Config) when is_list(Config) -> + ?line process_flag(trap_exit, true), + ?line Reason = make_ref(), + ?line Pid = spawn_link(fun() -> ?IM:please_call_exit(Reason) end), + ?line receive + {'EXIT',Pid,Reason} -> + ok; + {'EXIT',Pid,BadReason} -> + ?line ?t:fail({bad_message,BadReason}) + after 10000 -> + ?line ?t:fail(timeout) + end, + ok. + +otp_8310(doc) -> + "OTP-8310. Bugfixes lc/bc and andalso/orelse."; +otp_8310(Config) when is_list(Config) -> + ?line ok = ?IM:otp_8310(), + ok. + +applier(M, F, A) -> + Res = apply(M, F, A), + io:format("~p:~p(~p) => ~p\n", [M,F,A,Res]), + Res. + +%% +%% Evaluate in another process, to prevent the test_case process to become +%% interpreted. +%% + +spawn_eval(Fun) -> + Self = self(), + spawn_link(fun() -> Self ! (catch Fun()) end), + receive + Result -> + Result + end. diff --git a/lib/debugger/test/int_eval_SUITE_data/Makefile.src b/lib/debugger/test/int_eval_SUITE_data/Makefile.src new file mode 100644 index 0000000000..28a1432157 --- /dev/null +++ b/lib/debugger/test/int_eval_SUITE_data/Makefile.src @@ -0,0 +1,26 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + + +EFLAGS=+debug_info + +all: my_int_eval_module.@EMULATOR@ + +my_int_eval_module.@EMULATOR@: my_int_eval_module.erl + erlc $(EFLAGS) my_int_eval_module.erl diff --git a/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl b/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl new file mode 100644 index 0000000000..997ee6e17d --- /dev/null +++ b/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl @@ -0,0 +1,245 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(my_int_eval_module). +-stupid_attribute({a,b}). + +-export([ets_new/0,ets_delete/1,spawn_test/0,apply_test/1,external_call_test/1]). +-export([check_exports/1,check_module_info/2]). +-export([give_me_a_fun_0/0,give_me_a_fun_0/1,give_me_a_fun_1/2, + give_me_a_bad_fun/0, do_apply/1, do_apply/2]). +-export([please_call_exit/1,i_will_do_the_exit/1]). +-export([more_catch/1,more_nocatch/1,exit_me/0]). +-export([f/1, f_try/1, f_catch/1]). +-export([otp_5837/1, otp_8310/0]). + +%% Internal exports. +-export([echo/2,my_subtract/2,catch_a_ball/0,throw_a_ball/0]). +-export([i_am_exported/1]). + +-import(lists, [member/2]). + +-define(line,put(test_server_loc,{?MODULE,?LINE}),). +-define(t,test_server). +-define(m,test_server:match). +-define(config,test_server:lookup_config). + +ets_new() -> + Id = ets:new(my_int_eval_table, [private]), + Id. + +ets_delete(Tab) -> + ets:delete(Tab). + +%% Spawning. + +spawn_test() -> + Term = {a,tuple}, + Pid = spawn_link(?MODULE, echo, [self(),Term]), + receive + {result,Pid,Term} -> ok; + Other -> {bad_response,Other} + after 5000 -> + timeout + end. + +echo(Parent, Term) -> + Parent ! {result,self(),Term}. + +%% Applying. + +apply_test(Fun) -> + 42 = Fun(number(2), number(40)), + 12 = apply(Fun, [number(7),number(5)]), + + Mod = module(), + Func = func(), + [a] = Mod:my_subtract(same([a,b,c]), same([b,c])), + [a,b] = Mod:Func(same([a,b,c]), same([c])), + [a,b,d] = ?MODULE:Func(same([a,b,c,d]), same([c])), + [d,e] = apply(Mod, Func, [same([d,e,f]), same([f])]), + [3] = apply(?MODULE, Func, [same([3,4]),same([4])]), + + %% This is obsolete, but it should work anyway. + HomeMadeFun = {?MODULE,my_subtract}, + [a] = HomeMadeFun(same([a,x,c]), same([x,c])), + [x] = apply(HomeMadeFun, [[x,y],[y,z]]), + + ok. + +number(X) -> {number,X}. +module() -> ?MODULE. +func() -> my_subtract. +same(X) -> X. + +my_subtract(X, Y) -> X -- Y. + +%% Catch and throw. + +catch_a_ball() -> + {a,ball} = (catch throw_a_ball()), + ok. + +throw_a_ball() -> + throw({a,ball}), + not_ok. + +exit_me() -> + exit({int,exit}). + +more_catch(Fun) -> + case catch lists:filter(Fun, [a]) of + {'EXIT', {_, exit}} -> + ok; + Else -> Else + end. + +more_nocatch(Fun) -> + lists:filter(Fun, [a]). + +%% External calls. + +external_call_test(Data) -> + {'EXIT',{undef,[{?MODULE,not_exported,[42,Data]}|_]}} = + (catch ?MODULE:not_exported(42, Data)), + {yes,Data} = i_am_exported(Data), + {yes,Data} = ?MODULE:i_am_exported(Data), + + %% Excercise the function cache in the interpreter. + + {ok,Data,[a,b]} = not_exported(Data, [a,b]), + {yes,Data} = i_am_exported(Data), + {ok,Data,[a,b]} = not_exported(Data, [a,b]), + {'EXIT',{undef,[{?MODULE,not_exported,[7,Data]}|_]}} = + (catch ?MODULE:not_exported(7, Data)), + {yes,Data} = ?MODULE:i_am_exported(Data), + ok. + +not_exported(N, D) -> + {ok,N,D}. + +i_am_exported(D) -> + {yes,D}. + +%% The module_info/0,1 functions and list comprehensions (funs). + +check_exports(Exp) -> + %% Check the structure of the export list and that there are more + %% than 4 elements. + + Exp = [{F,A} || {F,A} <- Exp, erlang:is_atom(F), erlang:is_integer(A)], + case length(Exp) of + Len when Len > 4 -> ok + end. + +check_module_info(ModInfo, Exports) -> + ModInfo = module_info(), + Exports = module_info(exports), + ok. + +%% Testcase apply_interpreted_fun/1. + +give_me_a_fun_0() -> + fun() -> perfectly_alright end. + +give_me_a_fun_0(Term) -> + fun() -> {ok,Term} end. + +give_me_a_fun_1(Min, Max) -> + Seq = lists:seq(Min, Max), + fun (L) when list(L) -> + [Info || {Key,Info} <- L, lists:member(Key, Seq)]; + (T) when tuple(T) -> + L = tuple_to_list(T), + F = fun({Key,Info}) -> + case lists:member(Key, Seq) of + true -> Info; + false -> false + end + end, + list_to_tuple(lists:map(F, L)) + end. + +give_me_a_bad_fun() -> + fun(Arg) -> erlang:error(Arg) end. + +do_apply(Fun) -> + Fun(). +do_apply(Fun, Arg) -> + Fun(Arg). + + +please_call_exit(Reason) -> + put(asked_to_call_exit, Reason), + put(will_call_my_good_friend, ''), + Res = int_eval_SUITE:applier(?MODULE, i_will_do_the_exit, [Reason]), + + %% We don't want a tail-recursive call above. + io:format("Returned from exit/1 -- how strange\n"). + +i_will_do_the_exit(Reason) -> + exit(Reason). + +f(Arg) -> + g(Arg). + +f_try(Arg) -> + try g(Arg) + catch + Class:Reason -> + {Class, Reason} + end. + +f_catch(Arg) -> + catch g(Arg). + +g({error, Reason}) -> + erlang:error(Reason); +g({exit, Reason}) -> + erlang:exit(Reason); +g({throw, Reason}) -> + erlang:throw(Reason); +g(Value) -> + Value. + +otp_5837(N) -> + n(N). + +n(N) -> + lists:map(fun(X) when N==X -> + yes; + (_) -> + no + end, + [1,2,3,4]). + +otp_8310() -> + a = if (false orelse a) =:= a -> a; true -> b end, + F1 = fun() -> a end, + {'EXIT',{{bad_filter,a},_}} = + (catch {a, [X || X <- [1,2,3], _ = F1()]}), + F2 = fun() -> << 3:8 >> end, + {'EXIT',{{bad_filter,<<3>>},_}} = + (catch {a, << << X >> || << X >> <= << 7:8 >>,_ = F2() >>}), + {'EXIT',{{bad_generator,a},_}} = + (catch {a, [X || X <- a]}), + {'EXIT',{{bad_generator,b},_}} = + (catch {a, << <<X>> || << X >> <= b >>}), + ok. diff --git a/lib/debugger/test/lc_SUITE.erl b/lib/debugger/test/lc_SUITE.erl new file mode 100644 index 0000000000..a22a689ec8 --- /dev/null +++ b/lib/debugger/test/lc_SUITE.erl @@ -0,0 +1,74 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(lc_SUITE). + +-author('bjorn@erix.ericsson.se'). +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + basic/1]). + +-include("test_server.hrl"). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [basic]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +basic(Config) when list(Config) -> + ?line L0 = lists:seq(1, 10), + ?line L1 = my_map(fun(X) -> {x,X} end, L0), + ?line L1 = [{x,X} || X <- L0], + ?line L0 = my_map(fun({x,X}) -> X end, L1), + ?line [1,2,3,4,5] = [X || X <- L0, X < 6], + ?line [4,5,6] = [X || X <- L0, X > 3, X < 7], + ?line [] = [X || X <- L0, X > 32, X < 7], + ?line [1,3,5,7,9] = [X || X <- L0, odd(X)], + + %% Error cases. + ?line [] = [X || X <- L1, X+1 < 2], + ?line [] = [{xx,X} || X <- L0, element(2, X) == no_no_no], + ?line {'EXIT',_} = (catch [X || X <- L1, odd(X)]), + + ok. + +my_map(F, L) -> + [F(X) || X <- L]. + +odd(X) -> + X rem 2 == 1. diff --git a/lib/debugger/test/record_SUITE.erl b/lib/debugger/test/record_SUITE.erl new file mode 100644 index 0000000000..06fd01555e --- /dev/null +++ b/lib/debugger/test/record_SUITE.erl @@ -0,0 +1,252 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%% Purpose : Test records. + +-module(record_SUITE). + +-include("test_server.hrl"). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + errors/1,record_test/1,eval_once/1]). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [errors,record_test,eval_once]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +-record(foo, {a,b,c,d}). +-record(bar, {a,b,c,d}). +-record(barf, {a,b,c,d,e}). + +errors(Config) when is_list(Config) -> + Foo = #foo{a=1,b=2,c=3,d=4}, + ?line #foo{a=19,b=42,c=3,d=4} = update_foo(Foo, 19, 42), + + ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19)), + ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35)), + ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35, 17)), + ?line {'EXIT',{{badrecord,bar},_}} = (catch update_foo_bar(Foo, 19, 35, 17, 42)), + + ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19)), + ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35)), + ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35, 17)), + ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, 35, 17, 42)), + ?line {'EXIT',{{badrecord,barf},_}} = (catch update_foo_barf(Foo, 19, + 35, 17, 42, -2)), + + ok. + +update_foo(#foo{}=R, A, B) -> + R#foo{a=A,b=B}. + +update_foo_bar(#foo{}=R, A) -> + R#bar{a=A}. + +update_foo_bar(#foo{}=R, A, _B) -> + R#bar{a=A,b=A}. + +update_foo_bar(#foo{}=R, A, _B, C) -> + R#bar{a=A,b=A,c=C}. + +update_foo_bar(#foo{}=R, A, _B, C, D) -> + R#bar{a=A,b=A,c=C,d=D}. + +update_foo_barf(#foo{}=R, A) -> + R#barf{a=A}. + +update_foo_barf(#foo{}=R, A, _B) -> + R#barf{a=A,b=A}. + +update_foo_barf(#foo{}=R, A, _B, C) -> + R#barf{a=A,b=A,c=C}. + +update_foo_barf(#foo{}=R, A, _B, C, D) -> + R#barf{a=A,b=A,c=C,d=D}. + +update_foo_barf(#foo{}=R, A, _B, C, D, E) -> + R#barf{a=A,b=A,c=C,d=D,e=E}. + + +-define(TrueGuard(Expr), if Expr -> ok; true -> ?t:fail() end). +-define(FalseGuard(Expr), if Expr -> ?t:fail(); true -> ok end). + +record_test(Config) when is_list(Config) -> + ?line true = is_record(#foo{}, foo), + ?line false = is_record(#foo{}, barf), + ?line false = is_record({foo}, foo), + + ?line true = erlang:is_record(#foo{}, foo), + ?line false = erlang:is_record(#foo{}, barf), + ?line false = erlang:is_record({foo}, foo), + + ?line false = is_record([], foo), + ?line false = is_record(Config, foo), + + ?line ?TrueGuard(is_record(#foo{}, foo)), + ?line ?FalseGuard(is_record(#foo{}, barf)), + ?line ?FalseGuard(is_record({foo}, foo)), + + ?line ?TrueGuard(erlang:is_record(#foo{}, foo)), + ?line ?FalseGuard(erlang:is_record(#foo{}, barf)), + ?line ?FalseGuard(erlang:is_record({foo}, foo)), + + ?line ?FalseGuard(is_record([], foo)), + ?line ?FalseGuard(is_record(Config, foo)), + + %% 'not is_record/2' to test guard optimization. + + ?line ?FalseGuard(not is_record(#foo{}, foo)), + ?line ?TrueGuard(not is_record(#foo{}, barf)), + ?line ?TrueGuard(not is_record({foo}, foo)), + + ?line ?FalseGuard(not erlang:is_record(#foo{}, foo)), + ?line ?TrueGuard(not erlang:is_record(#foo{}, barf)), + ?line ?TrueGuard(not erlang:is_record({foo}, foo)), + + Foo = id(#foo{}), + ?line ?FalseGuard(not erlang:is_record(Foo, foo)), + ?line ?TrueGuard(not erlang:is_record(Foo, barf)), + + ?line ?TrueGuard(not is_record(Config, foo)), + + ?line ?TrueGuard(not is_record(a, foo)), + ?line ?TrueGuard(not is_record([], foo)), + + %% Pass non-literal first argument. + + ?line true = is_record(id(#foo{}), foo), + ?line false = is_record(id(#foo{}), barf), + ?line false = is_record(id({foo}), foo), + + ?line true = erlang:is_record(id(#foo{}), foo), + ?line false = erlang:is_record(id(#foo{}), barf), + ?line false = erlang:is_record(id({foo}), foo), + + NoRec1 = id(blurf), + NoRec2 = id([]), + + ?line ?TrueGuard(not is_record(NoRec1, foo)), + ?line ?TrueGuard(not is_record(NoRec2, foo)), + + %% Force the use of guard bifs by using the 'xor' operation. + + False = id(false), + ?line ?TrueGuard(is_record(#foo{}, foo) xor False), + ?line ?FalseGuard(is_record(#foo{}, barf) xor False), + ?line ?FalseGuard(is_record({foo}, foo) xor False ), + + ?line ?TrueGuard(is_record(Foo, foo) xor False), + ?line ?FalseGuard(is_record(Foo, barf) xor False), + + + %% Implicit guards by using a list comprehension. + + List = id([1,#foo{a=2},3,#bar{d=4},5,#foo{a=6},7]), + + ?line [#foo{a=2},#foo{a=6}] = [X || X <- List, is_record(X, foo)], + ?line [#bar{d=4}] = [X || X <- List, is_record(X, bar)], + ?line [1,#foo{a=2},3,5,#foo{a=6},7] = + [X || X <- List, not is_record(X, bar)], + ?line [1,3,5,7] = + [X || X <- List, ((not is_record(X, bar)) and (not is_record(X, foo)))], + ?line [#foo{a=2},#bar{d=4},#foo{a=6}] = + [X || X <- List, ((is_record(X, bar)) or (is_record(X, foo)))], + ?line [1,3,#bar{d=4}] = + [X || X <- List, ((is_record(X, bar)) or (X < 5))], + + ?line MyList = [#foo{a=3},x,[],{a,b}], + ?line [#foo{a=3}] = [X || X <- MyList, is_record(X, foo)], + ?line [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo)], + ?line [#foo{a=3}] = [X || X <- MyList, begin is_record(X, foo) end], + ?line [x,[],{a,b}] = [X || X <- MyList, begin not is_record(X, foo) end], + ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, is_record(X, foo) or + not is_binary(X)], + ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo) or + not is_binary(X)], + ?line [#foo{a=3}] = [X || X <- MyList, is_record(X, foo) or is_reference(X)], + ?line [x,[],{a,b}] = [X || X <- MyList, not is_record(X, foo) or + is_reference(X)], + ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, + begin is_record(X, foo) or + not is_binary(X) end], + ?line [#foo{a=3},x,[],{a,b}] = [X || X <- MyList, + begin not is_record(X, foo) or + not is_binary(X) end], + ?line [#foo{a=3}] = [X || X <- MyList, + begin is_record(X, foo) or is_reference(X) end], + ?line [x,[],{a,b}] = [X || X <- MyList, + begin not is_record(X, foo) or + is_reference(X) end], + ok. + +eval_once(Config) when is_list(Config) -> + ?line once(fun(GetRec) -> + true = erlang:is_record(GetRec(), foo) + end, #foo{}), + ?line once(fun(GetRec) -> + (GetRec())#foo{a=1} + end, #foo{}), + ?line once(fun(GetRec) -> + (GetRec())#foo{a=1,b=2} + end, #foo{}), + ?line once(fun(GetRec) -> + (GetRec())#foo{a=1,b=2,c=3} + end, #foo{}), + ?line once(fun(GetRec) -> + (GetRec())#foo{a=1,b=2,c=3,d=4} + end, #foo{}), + ok. + +once(Test, Record) -> + put(?MODULE, 0), + GetRec = fun() -> + put(?MODULE, 1+get(?MODULE)), + Record + end, + Result = Test(GetRec), + case get(?MODULE) of + 1 -> ok; + N -> + io:format("Evaluated ~w times\n", [N]), + ?t:fail() + end, + Result. + +id(I) -> I. diff --git a/lib/debugger/test/test_lib.erl b/lib/debugger/test/test_lib.erl new file mode 100644 index 0000000000..541375e64a --- /dev/null +++ b/lib/debugger/test/test_lib.erl @@ -0,0 +1,29 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + + +-module(test_lib). + +-export([interpret/1]). + +interpret(Mod) when atom(Mod) -> + case lists:member(Mod, int:interpreted()) of + true -> ok; + false -> {module,Mod} = i:ii(Mod) + end. diff --git a/lib/debugger/test/trycatch_SUITE.erl b/lib/debugger/test/trycatch_SUITE.erl new file mode 100644 index 0000000000..5901cdc9e5 --- /dev/null +++ b/lib/debugger/test/trycatch_SUITE.erl @@ -0,0 +1,796 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(trycatch_SUITE). + +-export([all/1,init_per_testcase/2,fin_per_testcase/2,init_all/1,finish_all/1, + basic/1,lean_throw/1,try_of/1,try_after/1,%after_bind/1, + catch_oops/1,after_oops/1,eclectic/1,rethrow/1, + nested_of/1,nested_catch/1,nested_after/1]). + +-include("test_server.hrl"). + +all(suite) -> + [{conf,init_all,cases(),finish_all}]. + +cases() -> + [basic,lean_throw,try_of,try_after,%after_bind, + catch_oops,after_oops,eclectic,rethrow, + nested_of,nested_catch,nested_after]. + +init_per_testcase(_Case, Config) -> + test_lib:interpret(?MODULE), + Dog = test_server:timetrap(?t:minutes(1)), + [{watchdog,Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +init_all(Config) when is_list(Config) -> + ?line test_lib:interpret(?MODULE), + ?line true = lists:member(?MODULE, int:interpreted()), + ok. + +finish_all(Config) when is_list(Config) -> + ok. + +basic(Conf) when is_list(Conf) -> + ?line 2 = + try my_div(4, 2) + catch + Class:Reason -> {Class,Reason} + end, + ?line error = + try my_div(1, 0) + catch + error:badarith -> error + end, + ?line error = + try 1/0 + catch + error:badarith -> error + end, + ?line ok = + try my_add(53, atom) + catch + error:badarith -> ok + end, + ?line exit_nisse = + try exit(nisse) + catch + exit:nisse -> exit_nisse + end, + ?line ok = + try throw(kalle) + catch + kalle -> ok + end, + + %% Try some stuff where the compiler will optimize away the try. + + V = id({a,variable}), + ?line V = try V catch nisse -> error end, + ?line 42 = try 42 catch nisse -> error end, + ?line [V] = try [V] catch nisse -> error end, + ?line {ok,V} = try {ok,V} catch nisse -> error end, + + %% Same idea, but use an after too. + + ?line V = try V catch nisse -> error after after_call() end, + ?line after_clean(), + ?line 42 = try 42 after after_call() end, + ?line after_clean(), + ?line [V] = try [V] catch nisse -> error after after_call() end, + ?line after_clean(), + ?line {ok,V} = try {ok,V} after after_call() end, + + %% Try/of + ?line ok = try V of + {a,variable} -> ok + catch nisse -> erro + end, + + ok. + +after_call() -> + put(basic, after_was_called). + +after_clean() -> + after_was_called = erase(basic). + +lean_throw(Conf) when is_list(Conf) -> + ?line {throw,kalle} = + try throw(kalle) + catch + Kalle -> {throw,Kalle} + end, + ?line {exit,kalle} = + try exit(kalle) + catch + Throw1 -> {throw,Throw1}; + exit:Reason1 -> {exit,Reason1} + end, + ?line {exit,kalle} = + try exit(kalle) + catch + exit:Reason2 -> {exit,Reason2}; + Throw2 -> {throw,Throw2} + end, + ?line {exit,kalle} = + try try exit(kalle) + catch + Throw3 -> {throw,Throw3} + end + catch + exit:Reason3 -> {exit,Reason3} + end, + ok. + +try_of(Conf) when is_list(Conf) -> + ?line {ok,{some,content}} = + try_of_1({value,{good,{some,content}}}), + ?line {error,[other,content]} = + try_of_1({value,{bad,[other,content]}}), + ?line {caught,{exit,{ex,it,[reason]}}} = + try_of_1({exit,{ex,it,[reason]}}), + ?line {caught,{throw,[term,{in,a,{tuple}}]}} = + try_of_1({throw,[term,{in,a,{tuple}}]}), + ?line {caught,{error,[bad,arg]}} = + try_of_1({error,[bad,arg]}), + ?line {caught,{error,badarith}} = + try_of_1({'div',{1,0}}), + ?line {caught,{error,badarith}} = + try_of_1({'add',{a,0}}), + ?line {caught,{error,badarg}} = + try_of_1({'abs',x}), + ?line {caught,{error,function_clause}} = + try_of_1(illegal), + ?line {error,{try_clause,{some,other_garbage}}} = + try try_of_1({value,{some,other_garbage}}) + catch error:Reason -> {error,Reason} + end, + ok. + +try_of_1(X) -> + try foo(X) of + {good,Y} -> {ok,Y}; + {bad,Y} -> {error,Y} + catch + Class:Reason -> + {caught,{Class,Reason}} + end. + +try_after(Conf) when is_list(Conf) -> + ?line {{ok,[some,value],undefined},finalized} = + try_after_1({value,{ok,[some,value]}},finalized), + ?line {{error,badarith,undefined},finalized} = + try_after_1({'div',{1,0}},finalized), + ?line {{error,badarith,undefined},finalized} = + try_after_1({'add',{1,a}},finalized), + ?line {{error,badarg,undefined},finalized} = + try_after_1({'abs',a},finalized), + ?line {{error,[the,{reason}],undefined},finalized} = + try_after_1({error,[the,{reason}]},finalized), + ?line {{throw,{thrown,[reason]},undefined},finalized} = + try_after_1({throw,{thrown,[reason]}},finalized), + ?line {{exit,{exited,{reason}},undefined},finalized} = + try_after_1({exit,{exited,{reason}}},finalized), + ?line {{error,function_clause,undefined},finalized} = + try_after_1(function_clause,finalized), + ?line ok = + try try_after_1({'add',{1,1}}, finalized) + catch + error:{try_clause,2} -> ok + end, + ?line finalized = erase(try_after), + ?line ok = + try try foo({exit,[reaso,{n}]}) + after put(try_after, finalized) + end + catch + exit:[reaso,{n}] -> ok + end, + ok. + +try_after_1(X, Y) -> + erase(try_after), + Try = + try foo(X) of + {ok,Value} -> {ok,Value,get(try_after)} + catch + Reason -> {throw,Reason,get(try_after)}; + error:Reason -> {error,Reason,get(try_after)}; + exit:Reason -> {exit,Reason,get(try_after)} + after + put(try_after, Y) + end, + {Try,erase(try_after)}. + +-ifdef(begone). + +after_bind(Conf) when is_list(Conf) -> + V = [make_ref(),self()|value], + ?line {value,{value,V}} = + after_bind_1({value,V}, V, {value,V}), + ok. + +after_bind_1(X, V, Y) -> + try + Try = + try foo(X) of + V -> value + catch + C1:V -> {caught,C1} + after + After = foo(Y) + end, + {Try,After} + of + V -> {value,V} + catch + C:D -> {caught,{C,D}} + end. + +-endif. + +catch_oops(Conf) when is_list(Conf) -> + V = {v,[a,l|u],{e},self()}, + ?line {value,V} = catch_oops_1({value,V}), + ?line {value,1} = catch_oops_1({'div',{1,1}}), + ?line {error,badarith} = catch_oops_1({'div',{1,0}}), + ?line {error,function_clause} = catch_oops_1(function_clause), + ?line {throw,V} = catch_oops_1({throw,V}), + ?line {exit,V} = catch_oops_1({exit,V}), + ok. + +catch_oops_1(X) -> + Ref = make_ref(), + try try foo({error,Ref}) + catch + error:Ref -> + foo(X) + end of + Value -> {value,Value} + catch + Class:Data -> {Class,Data} + end. + + + +after_oops(Conf) when is_list(Conf) -> + V = {self(),make_ref()}, + ?line {{value,V},V} = after_oops_1({value,V}, {value,V}), + ?line {{exit,V},V} = after_oops_1({exit,V}, {value,V}), + ?line {{error,V},undefined} = after_oops_1({value,V}, {error,V}), + ?line {{error,function_clause},undefined} = + after_oops_1({exit,V}, function_clause), + ok. + +after_oops_1(X, Y) -> + erase(after_oops), + Try = + try try foo(X) + after + put(after_oops, foo(Y)) + end of + V -> {value,V} + catch + C:D -> {C,D} + end, + {Try,erase(after_oops)}. + + + +eclectic(Conf) when is_list(Conf) -> + V = {make_ref(),3.1415926535,[[]|{}]}, + ?line {{value,{value,V},V},V} = + eclectic_1({foo,{value,{value,V}}}, undefined, {value,V}), + ?line {{'EXIT',{V,[{?MODULE,foo,_}|_]}},V} = + eclectic_1({catch_foo,{error,V}}, undefined, {value,V}), + ?line {{error,{exit,V},{'EXIT',V}},V} = + eclectic_1({foo,{error,{exit,V}}}, error, {value,V}), + ?line {{value,{value,V},V},{'EXIT',{badarith,[{?MODULE,my_add,_}|_]}}} = + eclectic_1({foo,{value,{value,V}}}, undefined, {'add',{0,a}}), + ?line {{'EXIT',V},V} = + eclectic_1({catch_foo,{exit,V}}, undefined, {throw,V}), + ?line {{error,{'div',{1,0}},{'EXIT',{badarith,[{?MODULE,my_div,_}|_]}}}, {'EXIT',V}} = + eclectic_1({foo,{error,{'div',{1,0}}}}, error, {exit,V}), + ?line {{{error,V},{'EXIT',{V,[{?MODULE,foo,_}|_]}}},{'EXIT',V}} = + eclectic_1({catch_foo,{throw,{error,V}}}, undefined, {exit,V}), + %% + ?line {{value,{value,{value,V},V}},V} = + eclectic_2({value,{value,V}}, undefined, {value,V}), + ?line {{value,{throw,{value,V},V}},V} = + eclectic_2({throw,{value,V}}, throw, {value,V}), + ?line {{caught,{'EXIT',V}},undefined} = + eclectic_2({value,{value,V}}, undefined, {exit,V}), + ?line {{caught,{'EXIT',{V,[{?MODULE,foo,_}|_]}}},undefined} = + eclectic_2({error,{value,V}}, throw, {error,V}), + ?line {{caught,{'EXIT',{badarg,[{erlang,abs,[V]}|_]}}},V} = + eclectic_2({value,{'abs',V}}, undefined, {value,V}), + ?line {{caught,{'EXIT',{badarith,[{?MODULE,my_add,_}|_]}}},V} = + eclectic_2({exit,{'add',{0,a}}}, exit, {value,V}), + ?line {{caught,{'EXIT',V}},undefined} = + eclectic_2({value,{error,V}}, undefined, {exit,V}), + ?line {{caught,{'EXIT',{V,[{?MODULE,foo,_}|_]}}},undefined} = + eclectic_2({throw,{'div',{1,0}}}, throw, {error,V}), + ok. + +eclectic_1(X, C, Y) -> + erase(eclectic), + Done = make_ref(), + Try = + try case X of + {catch_foo,V} -> catch {Done,foo(V)}; + {foo,V} -> {Done,foo(V)} + end of + {Done,D} -> {value,D,catch foo(D)}; + {'EXIT',_}=Exit -> Exit; + D -> {D,catch foo(D)} + catch + C:D -> {C,D,catch foo(D)} + after + put(eclectic, catch foo(Y)) + end, + {Try,erase(eclectic)}. + +eclectic_2(X, C, Y) -> + Done = make_ref(), + erase(eclectic), + Catch = + case + catch + {Done, + try foo(X) of + V -> {value,V,foo(V)} + catch + C:D -> {C,D,foo(D)} + after + put(eclectic, foo(Y)) + end} of + {Done,Z} -> {value,Z}; + Z -> {caught,Z} + end, + {Catch,erase(eclectic)}. + +rethrow(Conf) when is_list(Conf) -> + V = {a,[b,{c,self()},make_ref]}, + ?line {value2,value1} = + rethrow_1({value,V}, V), + ?line {caught2,{error,V}} = + rethrow_2({error,V}, undefined), + ?line {caught2,{exit,V}} = + rethrow_1({exit,V}, error), + ?line {caught2,{throw,V}} = + rethrow_1({throw,V}, undefined), + ?line {caught2,{throw,V}} = + rethrow_2({throw,V}, undefined), + ?line {caught2,{error,badarith}} = + rethrow_1({'add',{0,a}}, throw), + ?line {caught2,{error,function_clause}} = + rethrow_2(function_clause, undefined), + ?line {caught2,{error,{try_clause,V}}} = + rethrow_1({value,V}, exit), + ?line {value2,{caught1,V}} = + rethrow_1({error,V}, error), + ?line {value2,{caught1,V}} = + rethrow_1({exit,V}, exit), + ?line {value2,caught1} = + rethrow_2({throw,V}, V), + ok. + +rethrow_1(X, C1) -> + try try foo(X) of + C1 -> value1 + catch + C1:D1 -> {caught1,D1} + end of + V2 -> {value2,V2} + catch + C2:D2 -> {caught2,{C2,D2}} + end. + +rethrow_2(X, C1) -> + try try foo(X) of + C1 -> value1 + catch + C1 -> caught1 % Implicit class throw: + end of + V2 -> {value2,V2} + catch + C2:D2 -> {caught2,{C2,D2}} + end. + + + +nested_of(Conf) when is_list(Conf) -> + V = {[self()|make_ref()],1.4142136}, + ?line {{value,{value1,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{value,{V,x1}},void,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{throw,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + {V,x4}, + finalized} = + nested_of_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + undefined, + finalized} = + nested_of_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}), + %% + ?line {{caught,{error,{try_clause,{V,x1}}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{value,{V,x1}},void,try_clause}, + void, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{exit,{V,x3}}}, + undefined, + {V,x4}, + finalized} = + nested_of_1({{value,{V,x1}},void,try_clause}, + void, {exit,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{throw,{V,x4}}}, + undefined, + undefined, + finalized} = + nested_of_1({{value,{V,x1}},void,try_clause}, + void, {exit,{V,x3}}, {throw,{V,x4}}), + %% + ?line {{value,{caught1,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{error,{V,x1}},error,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + {V,x4}, + finalized} = + nested_of_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}), + ?line {{caught,{error,badarg}}, + undefined, + undefined, + finalized} = + nested_of_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {'div',{17,0}}, {'abs',V}), + %% + ?line {{caught,{error,badarith}}, + {V,x3}, + {V,x4}, + finalized} = + nested_of_1({{'add',{2,c}},rethrow,void}, + void, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarg}}, + undefined, + {V,x4}, + finalized} = + nested_of_1({{'add',{2,c}},rethrow,void}, + void, {'abs',V}, {value,{V,x4}}), + ?line {{caught,{error,function_clause}}, + undefined, + undefined, + finalized} = + nested_of_1({{'add',{2,c}},rethrow,void}, + void, {'abs',V}, function_clause), + ok. + +nested_of_1({X1,C1,V1}, + X2, X3, X4) -> + erase(nested3), + erase(nested4), + erase(nested), + Self = self(), + Try = + try + try self() + of + Self -> + try + foo(X1) + of + V1 -> {value1,foo(X2)} + catch + C1:V1 -> {caught1,foo(X2)} + after + put(nested3, foo(X3)) + end + after + put(nested4, foo(X4)) + end + of + V -> {value,V} + catch + C:D -> {caught,{C,D}} + after + put(nested, finalized) + end, + {Try,erase(nested3),erase(nested4),erase(nested)}. + + + +nested_catch(Conf) when is_list(Conf) -> + V = {[make_ref(),1.4142136,self()]}, + ?line {{value,{value1,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{value,{V,x1}},void,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{throw,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + {V,x4}, + finalized} = + nested_catch_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {'div',{1,0}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + undefined, + finalized} = + nested_catch_1({{value,{V,x1}},void,{V,x1}}, + {throw,{V,x2}}, {'div',{1,0}}, {'add',{0,b}}), + %% + ?line {{caught,{error,{try_clause,{V,x1}}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{value,{V,x1}},void,try_clause}, + void, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{exit,{V,x3}}}, + undefined, + {V,x4}, + finalized} = + nested_catch_1({{value,{V,x1}},void,try_clause}, + void, {exit,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{throw,{V,x4}}}, + undefined, + undefined, + finalized} = + nested_catch_1({{value,{V,x1}},void,try_clause}, + void, {exit,{V,x3}}, {throw,{V,x4}}), + %% + ?line {{value,{caught1,{V,x2}}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{error,{V,x1}},error,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarith}}, + undefined, + {V,x4}, + finalized} = + nested_catch_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {'div',{17,0}}, {value,{V,x4}}), + ?line {{caught,{error,badarg}}, + undefined, + undefined, + finalized} = + nested_catch_1({{error,{V,x1}},error,{V,x1}}, + {'add',{1,c}}, {'div',{17,0}}, {'abs',V}), + %% + ?line {{caught,{error,badarith}}, + {V,x3}, + {V,x4}, + finalized} = + nested_catch_1({{'add',{2,c}},rethrow,void}, + void, {value,{V,x3}}, {value,{V,x4}}), + ?line {{caught,{error,badarg}}, + undefined, + {V,x4}, + finalized} = + nested_catch_1({{'add',{2,c}},rethrow,void}, + void, {'abs',V}, {value,{V,x4}}), + ?line {{caught,{error,function_clause}}, + undefined, + undefined, + finalized} = + nested_catch_1({{'add',{2,c}},rethrow,void}, + void, {'abs',V}, function_clause), + ok. + +nested_catch_1({X1,C1,V1}, + X2, X3, X4) -> + erase(nested3), + erase(nested4), + erase(nested), + Throw = make_ref(), + Try = + try + try throw(Throw) + catch + Throw -> + try + foo(X1) + of + V1 -> {value1,foo(X2)} + catch + C1:V1 -> {caught1,foo(X2)} + after + put(nested3, foo(X3)) + end + after + put(nested4, foo(X4)) + end + of + V -> {value,V} + catch + C:D -> {caught,{C,D}} + after + put(nested, finalized) + end, + {Try,erase(nested3),erase(nested4),erase(nested)}. + +nested_after(Conf) when is_list(Conf) -> + V = [{make_ref(),1.4142136,self()}], + ?line {value, + {V,x3}, + {value1,{V,x2}}, + finalized} = + nested_after_1({{value,{V,x1}},void,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}), + ?line {{caught,{error,{V,x2}}}, + {V,x3}, + undefined, + finalized} = + nested_after_1({{value,{V,x1}},void,{V,x1}}, + {error,{V,x2}}, {value,{V,x3}}), + ?line {{caught,{exit,{V,x3}}}, + undefined, + undefined, + finalized} = + nested_after_1({{value,{V,x1}},void,{V,x1}}, + {error,{V,x2}}, {exit,{V,x3}}), + %% + ?line {{caught,{error,{try_clause,{V,x1}}}}, + {V,x3}, + undefined, + finalized} = + nested_after_1({{value,{V,x1}},void,try_clause}, + void, {value,{V,x3}}), + ?line {{caught,{error,badarith}}, + undefined, + undefined, + finalized} = + nested_after_1({{value,{V,x1}},void,try_clause}, + void, {'div',{17,0}}), + %% + ?line {value, + {V,x3}, + {caught1,{V,x2}}, + finalized} = + nested_after_1({{throw,{V,x1}},throw,{V,x1}}, + {value,{V,x2}}, {value,{V,x3}}), + ?line {{caught,{error,badarith}}, + {V,x3}, + undefined, + finalized} = + nested_after_1({{throw,{V,x1}},throw,{V,x1}}, + {'add',{a,b}}, {value,{V,x3}}), + ?line {{caught,{error,badarg}}, + undefined, + undefined, + finalized} = + nested_after_1({{throw,{V,x1}},throw,{V,x1}}, + {'add',{a,b}}, {'abs',V}), + %% + ?line {{caught,{throw,{V,x1}}}, + {V,x3}, + undefined, + finalized} = + nested_after_1({{throw,{V,x1}},rethrow,void}, + void, {value,{V,x3}}), + ?line {{caught,{error,badarith}}, + undefined, + undefined, + finalized} = + nested_after_1({{throw,{V,x1}},rethrow,void}, + void, {'div',{1,0}}), + ok. + +nested_after_1({X1,C1,V1}, + X2, X3) -> + erase(nested3), + erase(nested4), + erase(nested), + Self = self(), + Try = + try + try self() + after + After = + try + foo(X1) + of + V1 -> {value1,foo(X2)} + catch + C1:V1 -> {caught1,foo(X2)} + after + put(nested3, foo(X3)) + end, + put(nested4, After) + end + of + Self -> value + catch + C:D -> {caught,{C,D}} + after + put(nested, finalized) + end, + {Try,erase(nested3),erase(nested4),erase(nested)}. + +foo({value,Value}) -> Value; +foo({'div',{A,B}}) -> + my_div(A, B); +foo({'add',{A,B}}) -> + my_add(A, B); +foo({'abs',X}) -> + my_abs(X); +foo({error,Error}) -> + erlang:error(Error); +foo({throw,Throw}) -> + erlang:throw(Throw); +foo({exit,Exit}) -> + erlang:exit(Exit); +foo({raise,{Class,Reason}}) -> + erlang:raise(Class, Reason). +%%foo(function_clause) -> % must not be defined! + +my_div(A, B) -> + A div B. + +my_add(A, B) -> + A + B. + +my_abs(X) -> abs(X). + +id(I) -> I. diff --git a/lib/erl_interface/doc/src/ei_connect.xml b/lib/erl_interface/doc/src/ei_connect.xml index 927395d1bf..36dfb149cc 100644 --- a/lib/erl_interface/doc/src/ei_connect.xml +++ b/lib/erl_interface/doc/src/ei_connect.xml @@ -116,7 +116,7 @@ int n = 0; struct in_addr addr; ei_cnode ec; -addr = inet_addr("150.236.14.75"); +addr.s_addr = inet_addr("150.236.14.75"); if (ei_connect_xinit(&ec, "chivas", "madonna", @@ -132,7 +132,7 @@ if (ei_connect_xinit(&ec, </p> <code type="none"><![CDATA[ if (ei_connect_init(&ec, "madonna", "cookie...", n++) < 0) { - fprintf("ERROR when initializing: %d",erl_errno); + fprintf(stderr,"ERROR when initializing: %d",erl_errno); exit(-1); } ]]></code> @@ -177,7 +177,7 @@ int fd = ei_connect(&ec, NODE); /*** Variant 2 ***/ struct in_addr addr; -addr = inet_addr(IP_ADDR); +addr.s_addr = inet_addr(IP_ADDR); fd = ei_xconnect(&ec, &addr, ALIVE); ]]></code> </desc> diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c index b1b79aa0e5..e191f3fbf0 100644 --- a/lib/erl_interface/src/connect/ei_connect.c +++ b/lib/erl_interface/src/connect/ei_connect.c @@ -502,10 +502,14 @@ int ei_connect_init(ei_cnode* ec, const char* this_node_name, return ERL_ERROR; } - if (this_node_name == NULL) + if (this_node_name == NULL) { sprintf(thisalivename, "c%d", (int) getpid()); - else + } else if (strlen(this_node_name) >= sizeof(thisalivename)) { + EI_TRACE_ERR0("ei_connect_init","ERROR: this_node_name too long"); + return ERL_ERROR; + } else { strcpy(thisalivename, this_node_name); + } if ((hp = ei_gethostbyname(thishostname)) == 0) { /* Looking up IP given hostname fails. We must be on a standalone diff --git a/lib/erl_interface/src/connect/ei_resolve.c b/lib/erl_interface/src/connect/ei_resolve.c index 42aeab22b1..24a030c468 100644 --- a/lib/erl_interface/src/connect/ei_resolve.c +++ b/lib/erl_interface/src/connect/ei_resolve.c @@ -601,7 +601,7 @@ struct hostent *ei_gethostbyaddr_r(const char *addr, #ifndef HAVE_GETHOSTBYNAME_R return my_gethostbyaddr_r(addr,length,type,hostp,buffer,buflen,h_errnop); #else -#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000)) +#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000) || defined(__DragonFly__)) struct hostent *result; gethostbyaddr_r(addr, length, type, hostp, buffer, buflen, &result, @@ -628,7 +628,7 @@ struct hostent *ei_gethostbyname_r(const char *name, #ifndef HAVE_GETHOSTBYNAME_R return my_gethostbyname_r(name,hostp,buffer,buflen,h_errnop); #else -#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000)) +#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000) || defined(__DragonFly__)) struct hostent *result; gethostbyname_r(name, hostp, buffer, buflen, &result, h_errnop); diff --git a/lib/erl_interface/src/epmd/epmd_port.c b/lib/erl_interface/src/epmd/epmd_port.c index 663b38d2d4..cf6122fafa 100644 --- a/lib/erl_interface/src/epmd/epmd_port.c +++ b/lib/erl_interface/src/epmd/epmd_port.c @@ -106,6 +106,12 @@ static int ei_epmd_r3_port (struct in_addr *addr, const char *alive, char ntoabuf[32]; #endif + if (len > sizeof(buf) - 3) + { + erl_errno = ERANGE; + return -1; + } + put16be(s,len); put8(s,EI_EPMD_PORT_REQ); strcpy(s,alive); @@ -164,6 +170,12 @@ static int ei_epmd_r4_port (struct in_addr *addr, const char *alive, #if defined(VXWORKS) char ntoabuf[32]; #endif + + if (len > sizeof(buf) - 3) + { + erl_errno = ERANGE; + return -1; + } put16be(s,len); put8(s,EI_EPMD_PORT2_REQ); diff --git a/lib/erl_interface/src/prog/erl_call.c b/lib/erl_interface/src/prog/erl_call.c index 93b84cbb36..448de9aa23 100644 --- a/lib/erl_interface/src/prog/erl_call.c +++ b/lib/erl_interface/src/prog/erl_call.c @@ -123,6 +123,10 @@ static int do_connect(ei_cnode *ec, char *nodename, struct call_flags *flags); static int read_stdin(char **buf); static void split_apply_string(char *str, char **mod, char **fun, char **args); +static void* ei_chk_malloc(size_t size); +static void* ei_chk_calloc(size_t nmemb, size_t size); +static void* ei_chk_realloc(void *old, size_t size); +static char* ei_chk_strdup(char *s); /*************************************************************************** @@ -132,7 +136,6 @@ static void split_apply_string(char *str, char **mod, ***************************************************************************/ /* FIXME isn't VxWorks to handle arguments differently? */ -/* FIXME check errors from malloc */ #if !defined(VXWORKS) int main(int argc, char *argv[]) @@ -165,8 +168,7 @@ int erl_call(int argc, char **argv) usage_arg(progname, "-sname "); } - flags.node = (char *) malloc(strlen(argv[i+1]) + 1); - strcpy(flags.node, argv[i+1]); + flags.node = ei_chk_strdup(argv[i+1]); i++; flags.use_long_name = 0; } else if (strcmp(argv[i], "-name") == 0) { /* -name NAME */ @@ -174,8 +176,7 @@ int erl_call(int argc, char **argv) usage_arg(progname, "-name "); } - flags.node = (char *) malloc(strlen(argv[i+1]) + 1); - strcpy(flags.node, argv[i+1]); + flags.node = ei_chk_strdup(argv[i+1]); i++; flags.use_long_name = 1; } else { @@ -210,16 +211,14 @@ int erl_call(int argc, char **argv) usage_arg(progname, "-c "); } flags.cookiep = 1; - flags.cookie = (char *) malloc(strlen(argv[i+1]) + 1); - strcpy(flags.cookie, argv[i+1]); + flags.cookie = ei_chk_strdup(argv[i+1]); i++; break; case 'n': if (i+1 >= argc) { usage_arg(progname, "-n "); } - flags.node = (char *) malloc(strlen(argv[i+1]) + 1); - strcpy(flags.node, argv[i+1]); + flags.node = ei_chk_strdup(argv[i+1]); flags.use_long_name = 1; i++; break; @@ -227,24 +226,21 @@ int erl_call(int argc, char **argv) if (i+1 >= argc) { usage_arg(progname, "-h "); } - flags.hidden = (char *) malloc(strlen(argv[i+1]) + 1); - strcpy(flags.hidden, argv[i+1]); + flags.hidden = ei_chk_strdup(argv[i+1]); i++; break; case 'x': if (i+1 >= argc) { usage_arg(progname, "-x "); } - flags.script = (char *) malloc(strlen(argv[i+1]) + 1); - strcpy(flags.script, argv[i+1]); + flags.script = ei_chk_strdup(argv[i+1]); i++; break; case 'a': if (i+1 >= argc) { usage_arg(progname, "-a "); } - flags.apply = (char *) malloc(strlen(argv[i+1]) + 1); - strcpy(flags.apply, argv[i+1]); + flags.apply = ei_chk_strdup(argv[i+1]); i++; break; case '?': @@ -304,8 +300,7 @@ int erl_call(int argc, char **argv) if (flags.hidden == NULL) { /* As default we are c17@gethostname */ i = flags.randomp ? (time(NULL) % 997) : 17; - /* FIXME allocates to small !!! */ - flags.hidden = (char *) malloc(3 + 2 ); /* c17 or cXYZ */ + flags.hidden = (char *) ei_chk_malloc(10 + 2 ); /* c17 or cXYZ */ #if defined(VXWORKS) sprintf(flags.hidden, "c%d", i < 0 ? (int) taskIdSelf() : i); @@ -330,17 +325,25 @@ int erl_call(int argc, char **argv) initWinSock(); #endif - gethostname(h_hostname, EI_MAXHOSTNAMELEN); + if (gethostname(h_hostname, EI_MAXHOSTNAMELEN) < 0) { + fprintf(stderr,"erl_call: failed to get host name: %d\n", errno); + exit(1); + } if ((hp = ei_gethostbyname(h_hostname)) == 0) { fprintf(stderr,"erl_call: can't resolve hostname %s\n", h_hostname); exit(1); } - /* If shortnames cut of the name at first '.' */ + /* If shortnames, cut off the name at first '.' */ if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) { *ct = '\0'; } - strcpy(h_hostname, hp->h_name); + strncpy(h_hostname, hp->h_name, EI_MAXHOSTNAMELEN); + h_hostname[EI_MAXHOSTNAMELEN] = '\0'; memcpy(&h_ipadr.s_addr, *hp->h_addr_list, sizeof(struct in_addr)); + if (strlen(h_alivename) + strlen(h_hostname) + 2 > sizeof(h_nodename)) { + fprintf(stderr,"erl_call: hostname too long: %s\n", h_hostname); + exit(1); + } sprintf(h_nodename, "%s@%s", h_alivename, h_hostname); if (ei_connect_xinit(&ec, h_hostname, h_alivename, h_nodename, @@ -368,11 +371,16 @@ int erl_call(int argc, char **argv) fprintf(stderr,"erl_call: can't get_hostent(%s)\n", host); exit(1); } - /* If shortnames cut of the name at first '.' */ + /* If shortnames, cut off the name at first '.' */ if (flags.use_long_name == 0 && (ct = strchr(hp->h_name, '.')) != NULL) { *ct = '\0'; } - strcpy(host_name, hp->h_name); + strncpy(host_name, hp->h_name, EI_MAXHOSTNAMELEN); + host_name[EI_MAXHOSTNAMELEN] = '\0'; + if (strlen(flags.node) + strlen(host_name) + 2 > sizeof(nodename)) { + fprintf(stderr,"erl_call: nodename too long: %s\n", flags.node); + exit(1); + } sprintf(nodename, "%s@%s", flags.node, host_name); /* @@ -401,7 +409,7 @@ int erl_call(int argc, char **argv) ei_encode_empty_list(NULL, &i); - p = (char *)malloc(i); + p = (char *)ei_chk_malloc(i); i = 0; /* Reset */ ei_encode_empty_list(p, &i); @@ -426,6 +434,10 @@ int erl_call(int argc, char **argv) if (flags.modp && (modname != NULL)) { char fname[256]; + if (strlen(modname) + 4 + 1 > sizeof(fname)) { + fprintf(stderr,"erl_call: module name too long: %s\n", modname); + exit(1); + } strcpy(fname, modname); strcat(fname, ".erl"); @@ -443,7 +455,7 @@ int erl_call(int argc, char **argv) ei_encode_binary(NULL, &i, module, modsize); ei_encode_empty_list(NULL, &i); - p = (char *)malloc(i); + p = (char *)ei_chk_malloc(i); i = 0; /* Reset */ ei_encode_list_header(p, &i, 2); @@ -476,7 +488,7 @@ int erl_call(int argc, char **argv) ei_encode_empty_list(NULL, &i); ei_encode_empty_list(NULL, &i); - p = (char *)malloc(i); + p = (char *)ei_chk_malloc(i); i = 0; /* Reset */ ei_encode_list_header(p, &i, 2); @@ -521,7 +533,7 @@ int erl_call(int argc, char **argv) ei_encode_binary(NULL, &i, evalbuf, len); ei_encode_empty_list(NULL, &i); - p = (char *)malloc(i); + p = (char *)ei_chk_malloc(i); i = 0; /* Reset */ ei_encode_list_header(p, &i, 1); @@ -719,32 +731,28 @@ static void split_apply_string(char *str, EAT(str); len = str-begin; - *mod = (char *) calloc(len + 1, sizeof(char)); + *mod = (char *) ei_chk_calloc(len + 1, sizeof(char)); memcpy(*mod, begin, len); SKIP_SPACE(str); if (*str == '\0') { - *fun = (char *) calloc(strlen(start)+1, sizeof(char)); - strcpy(*fun, start); - *args = (char *) calloc(strlen(empty_list)+1, sizeof(char)); - strcpy(*args, empty_list); + *fun = ei_chk_strdup(start); + *args = ei_chk_strdup(empty_list); return; } begin = str; EAT(str); len = str-begin; - *fun = (char *) calloc(len + 1, sizeof(char)); + *fun = (char *) ei_chk_calloc(len + 1, sizeof(char)); memcpy(*fun, begin, len); SKIP_SPACE(str); if (*str == '\0') { - *args = (char *) calloc(strlen(empty_list)+1, sizeof(char)); - strcpy(*args, empty_list); + *args = ei_chk_strdup(empty_list); return; } - *args = (char *) calloc(strlen(str) + 1, sizeof(char)); - strcpy(*args, str); + *args = ei_chk_strdup(str); return; @@ -760,7 +768,7 @@ static int read_stdin(char **buf) int bsize = BUFSIZ; int len = 0; int i; - char *tmp = (char *) malloc(bsize); + char *tmp = (char *) ei_chk_malloc(bsize); while (1) { if ((i = read(0, &tmp[len], bsize-len)) < 0) { @@ -772,7 +780,7 @@ static int read_stdin(char **buf) len += i; if ((len+50) > bsize) { bsize = len * 2; - tmp = (char *) realloc(tmp, bsize); + tmp = (char *) ei_chk_realloc(tmp, bsize); } else { continue; } @@ -809,7 +817,7 @@ static int get_module(char **mbuf, char **mname) } } /* while */ i = tmp - start; - *mname = (char *) calloc(i+1, sizeof(char)); + *mname = (char *) ei_chk_calloc(i+1, sizeof(char)); memcpy(*mname, start, i); } if (*mbuf) @@ -905,3 +913,51 @@ static void initWinSock(void) } } #endif + + +/*************************************************************************** + * + * Utility functions + * + ***************************************************************************/ + +static void* ei_chk_malloc(size_t size) +{ + void *p = malloc(size); + if (p == NULL) { + fprintf(stderr,"erl_call: insufficient memory\n"); + exit(1); + } + return p; +} + +static void* ei_chk_calloc(size_t nmemb, size_t size) +{ + void *p = calloc(nmemb, size); + if (p == NULL) { + fprintf(stderr,"erl_call: insufficient memory\n"); + exit(1); + } + return p; +} + +static void* ei_chk_realloc(void *old, size_t size) +{ + void *p = realloc(old, size); + if (!p) { + fprintf(stderr, "erl_call: cannot reallocate %u bytes of memory from %p\n", + (unsigned) size, old); + exit (1); + } + return p; +} + +static char* ei_chk_strdup(char *s) +{ + char *p = strdup(s); + if (p == NULL) { + fprintf(stderr,"erl_call: insufficient memory\n"); + exit(1); + } + return p; +} diff --git a/lib/et/src/et_wx_viewer.erl b/lib/et/src/et_wx_viewer.erl index 5cd3563aed..d42f8c0c86 100644 --- a/lib/et/src/et_wx_viewer.erl +++ b/lib/et/src/et_wx_viewer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. +%% Copyright Ericsson AB 2000-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1233,7 +1233,7 @@ create_main_window(S) -> [{flag, ?wxEXPAND}]), CanvasSizer = wxBoxSizer:new(?wxHORIZONTAL), - Canvas = wxPanel:new(Panel, []), + Canvas = wxPanel:new(Panel, [{style, ?wxFULL_REPAINT_ON_RESIZE}]), {CanvasW,CanvasH} = wxPanel:getSize(Canvas), ScrollBar = wxScrollBar:new(Panel, ?wxID_ANY, [{style, ?wxSB_VERTICAL}]), @@ -1244,7 +1244,13 @@ create_main_window(S) -> wxPanel:connect(Canvas, left_up), wxPanel:connect(Canvas, right_up), wxPanel:connect(Canvas, size), - wxPanel:connect(Canvas, paint), + Self = self(), + wxPanel:connect(Canvas, paint, [{callback, %% Needed on windows + fun(Ev, _) -> + DC = wxPaintDC:new(Canvas), + wxPaintDC:destroy(DC), + Self ! Ev + end}]), wxPanel:connect(Canvas, key_down), wxPanel:connect(Canvas, kill_focus), wxPanel:connect(Canvas, enter_window, [{skip, true}]), @@ -1437,6 +1443,7 @@ create_help_menu(Bar) -> clear_canvas(S) -> DC = wxClientDC:new(S#state.canvas), + wxDC:setBackground(DC, ?wxWHITE_BRUSH), %% Needed on mac wxDC:clear(DC), {CanvasW, CanvasH} = wxPanel:getSize(S#state.canvas), wxSizer:recalcSizes(S#state.canvas_sizer), diff --git a/lib/et/test/Makefile b/lib/et/test/Makefile index 9aedf96ce9..7227ae8fd8 100644 --- a/lib/et/test/Makefile +++ b/lib/et/test/Makefile @@ -72,7 +72,8 @@ release_spec: opt release_tests_spec: opt $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) et.spec $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR) - $(INSTALL_PROGRAM) ett $(INSTALL_PROGS) $(RELSYSDIR) + $(INSTALL_SCRIPT) ett $(RELSYSDIR) + $(INSTALL_DATA) $(INSTALL_PROGS) $(RELSYSDIR) # chmod -f -R u+w $(RELSYSDIR) # @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) diff --git a/lib/gs/doc/src/gs.xml b/lib/gs/doc/src/gs.xml index b1c7e505dc..f2182fc673 100644 --- a/lib/gs/doc/src/gs.xml +++ b/lib/gs/doc/src/gs.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>2000</year> - <year>2007</year> + <year>2010</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -32,6 +32,18 @@ <module>gs</module> <modulesummary>The Graphics System for Erlang.</modulesummary> <description> + <warning> + <p> + GS is not recommended for use in new applications. + Instead we recommend WX for applications that need a + graphical user interface. + </p> + <p> + GS is not maintained and we plan to deprecate and remove it from + the distribution as soon as possible, maybe already in the next + major release (R15). + </p> + </warning> <p>The Graphics System, GS, is easy to learn and designed to be portable to many different platforms.</p> <p>In the description below, the type <c><![CDATA[gsobj()]]></c> denotes a diff --git a/lib/gs/doc/src/gs_chapter1.xml b/lib/gs/doc/src/gs_chapter1.xml index cfcae94f7c..912d6e1ef9 100644 --- a/lib/gs/doc/src/gs_chapter1.xml +++ b/lib/gs/doc/src/gs_chapter1.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -31,6 +31,18 @@ <section> <title>Introduction</title> + <warning> + <p> + GS is not recommended for use in new applications. + Instead we recommend WX for applications that need a + graphical user interface. + </p> + <p> + GS is not maintained and we plan to deprecate and remove it from + the distribution as soon as possible, maybe already in the next + major release (R15). + </p> + </warning> <p>This section describes the general graphics interface to Erlang. This system was designed with the following requirements in mind:</p> <list type="bulleted"> <item>a graphics system which is easy to learn</item> diff --git a/lib/ic/test/Makefile b/lib/ic/test/Makefile new file mode 100644 index 0000000000..1142159d19 --- /dev/null +++ b/lib/ic/test/Makefile @@ -0,0 +1,277 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1998-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(IC_VSN) +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/ic_test + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +TEST_SPEC_FILE = ic.spec ic.spec.vxworks + + +IDL_FILES = + +COMPILER_TEST_FILES = \ + ic_SUITE_data/Corba.idl \ + ic_SUITE_data/Coss.idl \ + ic_SUITE_data/attr.idl \ + ic_SUITE_data/c_err1.idl \ + ic_SUITE_data/c_err2.idl \ + ic_SUITE_data/c_err3.idl \ + ic_SUITE_data/c_norm.idl \ + ic_SUITE_data/enum.idl \ + ic_SUITE_data/forward.idl \ + ic_SUITE_data/include.idl \ + ic_SUITE_data/include2.idl \ + ic_SUITE_data/include3.idl \ + ic_SUITE_data/inherit.idl \ + ic_SUITE_data/inherit_err.idl \ + ic_SUITE_data/inherit_warn.idl \ + ic_SUITE_data/mult_ids.idl \ + ic_SUITE_data/nasty.idl \ + ic_SUITE_data/one.idl \ + ic_SUITE_data/one_out.idl \ + ic_SUITE_data/one_raises.idl \ + ic_SUITE_data/one_followed.idl \ + ic_SUITE_data/one_void.idl \ + ic_SUITE_data/raises_reg.idl \ + ic_SUITE_data/struct.idl \ + ic_SUITE_data/syntax1.idl \ + ic_SUITE_data/syntax2.idl \ + ic_SUITE_data/syntax3.idl \ + ic_SUITE_data/syntax4.idl \ + ic_SUITE_data/syntax5.idl \ + ic_SUITE_data/syntax6.idl \ + ic_SUITE_data/type.idl \ + ic_SUITE_data/typeid.idl \ + ic_SUITE_data/u_case_mult.idl \ + ic_SUITE_data/u_mult.idl \ + ic_SUITE_data/u_norm.idl \ + ic_SUITE_data/u_type.idl \ + ic_SUITE_data/u_default.idl \ + ic_SUITE_data/undef_id.idl + + +COMPILER_TEST_FILES2 = \ + ic_register_SUITE_data/reg_m8.idl \ + ic_register_SUITE_data/reg_m9.idl \ + ic_register_SUITE_data/reg_m10.idl \ + ic_register_SUITE_data/reg_m11.idl \ + ic_register_SUITE_data/reg_m12.idl + + +COMPILER_TEST_FILES3 = \ + ic_pragma_SUITE_data/reg_m0.idl \ + ic_pragma_SUITE_data/reg_m1.idl \ + ic_pragma_SUITE_data/reg_m2.idl \ + ic_pragma_SUITE_data/reg_m3.idl \ + ic_pragma_SUITE_data/reg_m4.idl \ + ic_pragma_SUITE_data/reg_m5.idl \ + ic_pragma_SUITE_data/reg_m6.idl \ + ic_pragma_SUITE_data/reg_m7.idl \ + ic_pragma_SUITE_data/uggly.idl + + +COMPILER_TEST_FILES4 = \ + ic_be_SUITE_data/plain.idl + + +PREPROCESSOR_TEST_FILES = \ + ic_pp_SUITE_data/arg.idl \ + ic_pp_SUITE_data/cascade.idl \ + ic_pp_SUITE_data/comment.idl \ + ic_pp_SUITE_data/concat.idl \ + ic_pp_SUITE_data/define.idl \ + ic_pp_SUITE_data/if.idl \ + ic_pp_SUITE_data/if_zero.idl \ + ic_pp_SUITE_data/improp_nest_constr.idl \ + ic_pp_SUITE_data/inc.idl \ + ic_pp_SUITE_data/line.idl \ + ic_pp_SUITE_data/misc.idl \ + ic_pp_SUITE_data/nopara.idl \ + ic_pp_SUITE_data/predef.idl \ + ic_pp_SUITE_data/predef_time.idl \ + ic_pp_SUITE_data/self_ref.idl \ + ic_pp_SUITE_data/separate.idl \ + ic_pp_SUITE_data/swallow_sc.idl \ + ic_pp_SUITE_data/unintended_grp.idl + +C_CLIENT_ERL_SERVER_TEST_FILES = \ + c_client_erl_server_SUITE_data/Makefile.src \ + c_client_erl_server_SUITE_data/c_erl_test.idl \ + c_client_erl_server_SUITE_data/c_client.c \ + c_client_erl_server_SUITE_data/m_i_impl.erl + +C_CLIENT_ERL_SERVER_PROTO_TEST_FILES = \ + c_client_erl_server_proto_SUITE_data/Makefile.src \ + c_client_erl_server_proto_SUITE_data/c_erl_test.idl \ + c_client_erl_server_proto_SUITE_data/c_client.c \ + c_client_erl_server_proto_SUITE_data/my.c \ + c_client_erl_server_proto_SUITE_data/m_i_impl.erl + +C_CLIENT_ERL_SERVER_PROTO_TMO_TEST_FILES = \ + c_client_erl_server_proto_tmo_SUITE_data/Makefile.src \ + c_client_erl_server_proto_tmo_SUITE_data/c_erl_test.idl \ + c_client_erl_server_proto_tmo_SUITE_data/c_client.c \ + c_client_erl_server_proto_tmo_SUITE_data/my.c \ + c_client_erl_server_proto_tmo_SUITE_data/m_i_impl.erl + +ERL_CLIENT_C_SERVER_TEST_FILES = \ + erl_client_c_server_SUITE_data/Makefile.src \ + erl_client_c_server_SUITE_data/erl_c_test.idl \ + erl_client_c_server_SUITE_data/erl_client.erl \ + erl_client_c_server_SUITE_data/c_server.c \ + erl_client_c_server_SUITE_data/callbacks.c + +ERL_CLIENT_C_SERVER_PROTO_TEST_FILES = \ + erl_client_c_server_proto_SUITE_data/Makefile.src \ + erl_client_c_server_proto_SUITE_data/erl_c_test.idl \ + erl_client_c_server_proto_SUITE_data/erl_client.erl \ + erl_client_c_server_proto_SUITE_data/c_server.c \ + erl_client_c_server_proto_SUITE_data/callbacks.c + +JAVA_CLIENT_ERL_SERVER_TEST_FILES = \ + java_client_erl_server_SUITE_data/Makefile.src \ + java_client_erl_server_SUITE_data/java_erl_test.idl \ + java_client_erl_server_SUITE_data/JavaClient.java \ + java_client_erl_server_SUITE_data/m_i_impl.erl + +MODULES = \ + ic_SUITE \ + ic_register_SUITE \ + ic_pragma_SUITE \ + ic_pp_SUITE \ + ic_be_SUITE \ + c_client_erl_server_SUITE \ + c_client_erl_server_proto_SUITE \ + c_client_erl_server_proto_tmo_SUITE \ + erl_client_c_server_SUITE \ + erl_client_c_server_proto_SUITE \ + java_client_erl_server_SUITE + +GEN_MODULES = + +ERL_FILES = $(MODULES:%=%.erl) + +HRL_FILES = + +GEN_HRL_FILES = + + +GEN_FILES = \ + $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \ + $(GEN_MODULES=:%=$(IDLOUTDIR)/%.erl) + +GEN_TARGET_FILES = $(GEN_MODULES:%=$(IDLOUTDIR)/%.$(EMULATOR)) + +SUITE_TARGET_FILES = $(MODULES:%=%.$(EMULATOR)) + +TARGET_FILES = \ + $(GEN_TARGET_FILES) \ + $(SUITE_TARGET_FILES) + +# ---------------------------------------------------- +# PROGRAMS +# ---------------------------------------------------- + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_LOCAL_FLAGS += -pa $(ERL_TOP)/lib/orber/ebin -pa $(ERL_TOP)/lib/ic/ebin + +ERL_COMPILE_FLAGS += \ + $(ERL_LOCAL_FLAGS) \ + -pa $(ERL_TOP)/lib/test_server/ebin \ + -pa $(ERL_TOP)/lib/orber/ebin \ + -I$(ERL_TOP)/lib/orber \ + -I$(ERL_TOP)/lib/test_server/include + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +tests debug opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f errs core *~ + +docs: + +# ---------------------------------------------------- +# Special Targets +# ---------------------------------------------------- + + +# ---------------------------------------------------- +# Release Targets +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: + +release_docs_spec: + +release_tests_spec: tests + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DIR) $(RELSYSDIR)/ic_SUITE_data + $(INSTALL_DIR) $(RELSYSDIR)/ic_register_SUITE_data + $(INSTALL_DIR) $(RELSYSDIR)/ic_pragma_SUITE_data + $(INSTALL_DIR) $(RELSYSDIR)/ic_pp_SUITE_data + $(INSTALL_DIR) $(RELSYSDIR)/ic_be_SUITE_data + $(INSTALL_DIR) $(RELSYSDIR)/c_client_erl_server_SUITE_data + $(INSTALL_DIR) $(RELSYSDIR)/c_client_erl_server_proto_SUITE_data + $(INSTALL_DIR) $(RELSYSDIR)/c_client_erl_server_proto_tmo_SUITE_data + $(INSTALL_DIR) $(RELSYSDIR)/erl_client_c_server_SUITE_data + $(INSTALL_DIR) $(RELSYSDIR)/erl_client_c_server_proto_SUITE_data + $(INSTALL_DIR) $(RELSYSDIR)/java_client_erl_server_SUITE_data + $(INSTALL_DATA) $(IDL_FILES) $(TEST_SPEC_FILE) $(ERL_FILES) \ + $(RELSYSDIR) + $(INSTALL_DATA) $(COMPILER_TEST_FILES) $(RELSYSDIR)/ic_SUITE_data + $(INSTALL_DATA) $(COMPILER_TEST_FILES2) \ + $(RELSYSDIR)/ic_register_SUITE_data + $(INSTALL_DATA) $(COMPILER_TEST_FILES3) \ + $(RELSYSDIR)/ic_pragma_SUITE_data + $(INSTALL_DATA) $(COMPILER_TEST_FILES4) \ + $(RELSYSDIR)/ic_be_SUITE_data + $(INSTALL_DATA) $(PREPROCESSOR_TEST_FILES) \ + $(RELSYSDIR)/ic_pp_SUITE_data + $(INSTALL_DATA) $(C_CLIENT_ERL_SERVER_TEST_FILES) \ + $(RELSYSDIR)/c_client_erl_server_SUITE_data + $(INSTALL_DATA) $(C_CLIENT_ERL_SERVER_PROTO_TEST_FILES) \ + $(RELSYSDIR)/c_client_erl_server_proto_SUITE_data + $(INSTALL_DATA) $(C_CLIENT_ERL_SERVER_PROTO_TMO_TEST_FILES) \ + $(RELSYSDIR)/c_client_erl_server_proto_tmo_SUITE_data + $(INSTALL_DATA) $(ERL_CLIENT_C_SERVER_TEST_FILES) \ + $(RELSYSDIR)/erl_client_c_server_SUITE_data + $(INSTALL_DATA) $(ERL_CLIENT_C_SERVER_PROTO_TEST_FILES) \ + $(RELSYSDIR)/erl_client_c_server_proto_SUITE_data + $(INSTALL_DATA) $(SUITE_TARGET_FILES) $(RELSYSDIR) + $(INSTALL_DATA) $(JAVA_CLIENT_ERL_SERVER_TEST_FILES) \ + $(RELSYSDIR)/java_client_erl_server_SUITE_data diff --git a/lib/ic/test/c_client_erl_server_SUITE.erl b/lib/ic/test/c_client_erl_server_SUITE.erl new file mode 100644 index 0000000000..40c1395d10 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_SUITE.erl @@ -0,0 +1,315 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +%%---------------------------------------------------------------------- +%% Purpose : Test suite for c-client/erl-server +%%---------------------------------------------------------------------- + + +-module(c_client_erl_server_SUITE). +-include("test_server.hrl"). + +-export([init_per_testcase/2, fin_per_testcase/2, + all/1, void_test/1, long_test/1, long_long_test/1, + unsigned_short_test/1, unsigned_long_test/1, + unsigned_long_long_test/1, double_test/1, char_test/1, + wchar_test/1, octet_test/1, bool_test/1, struct_test/1, + struct2_test/1, seq1_test/1, seq2_test/1, seq3_test/1, + seq4_test/1, seq5_test/1, array1_test/1, array2_test/1, + enum_test/1, string1_test/1, string2_test/1, string3_test/1, + string4_test/1, pid_test/1, port_test/1, ref_test/1, term_test/1, + typedef_test/1, inline_sequence_test/1, term_sequence_test/1, + term_struct_test/1, wstring1_test/1]). + +-define(DEFAULT_TIMEOUT, 20000). +-define(PORT_TIMEOUT, 15000). +-define(ERLANG_SERVER_NAME, idl_erlang_server). +-define(C_CLIENT_NODE_NAME, c_client_idl_test). + +%% Add/remove code path and watchdog before/after each test case. +%% +init_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:add_patha(DataDir), + + %% Since other test suites use the module m_i, we have + %% to make sure we are using the right m_i module. + code:purge(m_i), + code:load_file(m_i), + + WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:del_path(DataDir), + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of IC with a C-client and an Erlang generic server. " + "The communication is via Erlang distribution."; +all(suite) -> + [void_test, long_test, long_long_test, unsigned_short_test, + unsigned_long_test, unsigned_long_long_test, double_test, + char_test, wchar_test, octet_test, bool_test, struct_test, + struct2_test, seq1_test, seq2_test, seq3_test, seq4_test, + seq5_test, array1_test, array2_test, enum_test, string1_test, + string2_test, string3_test, string4_test, pid_test, port_test, + ref_test, term_test, typedef_test, inline_sequence_test, + term_sequence_test, term_struct_test, wstring1_test]. + + +array1_test(doc) -> ""; +array1_test(suite) -> []; +array1_test(Config) -> + do_test(array1_test, Config). + +array2_test(doc) -> ""; +array2_test(suite) -> []; +array2_test(Config) -> + do_test(array2_test, Config). + +bool_test(doc) -> ""; +bool_test(suite) -> []; +bool_test(Config) -> + do_test(bool_test, Config). + +char_test(doc) -> ""; +char_test(suite) -> []; +char_test(Config) -> + do_test(char_test, Config). + +double_test(doc) -> ""; +double_test(suite) -> []; +double_test(Config) -> + do_test(double_test, Config). + +enum_test(doc) -> ""; +enum_test(suite) -> []; +enum_test(Config) -> + do_test(enum_test, Config). + +inline_sequence_test(doc) -> ""; +inline_sequence_test(suite) -> []; +inline_sequence_test(Config) -> + do_test(inline_sequence_test, Config). + +long_long_test(doc) -> ""; +long_long_test(suite) -> []; +long_long_test(Config) -> + do_test(long_long_test, Config). + +long_test(doc) -> ""; +long_test(suite) -> []; +long_test(Config) -> + do_test(long_test, Config). + +octet_test(doc) -> ""; +octet_test(suite) -> []; +octet_test(Config) -> + do_test(octet_test, Config). + +pid_test(doc) -> ""; +pid_test(suite) -> []; +pid_test(Config) -> + do_test(pid_test, Config). + +port_test(doc) -> ""; +port_test(suite) -> []; +port_test(Config) -> + do_test(port_test, Config). + +ref_test(doc) -> ""; +ref_test(suite) -> []; +ref_test(Config) -> + do_test(ref_test, Config). + +seq1_test(doc) -> ""; +seq1_test(suite) -> []; +seq1_test(Config) -> + do_test(seq1_test, Config). + +seq2_test(doc) -> ""; +seq2_test(suite) -> []; +seq2_test(Config) -> + do_test(seq2_test, Config). + +seq3_test(doc) -> ""; +seq3_test(suite) -> []; +seq3_test(Config) -> + do_test(seq3_test, Config). + +seq4_test(doc) -> ""; +seq4_test(suite) -> []; +seq4_test(Config) -> + do_test(seq4_test, Config). + +seq5_test(doc) -> ""; +seq5_test(suite) -> []; +seq5_test(Config) -> + do_test(seq5_test, Config). + +string1_test(doc) -> ""; +string1_test(suite) -> []; +string1_test(Config) -> + do_test(string1_test, Config). + +string2_test(doc) -> ""; +string2_test(suite) -> []; +string2_test(Config) -> + do_test(string2_test, Config). + +string3_test(doc) -> ""; +string3_test(suite) -> []; +string3_test(Config) -> + do_test(string3_test, Config). + +string4_test(doc) -> ""; +string4_test(suite) -> []; +string4_test(Config) -> + do_test(string4_test, Config). + +struct2_test(doc) -> ""; +struct2_test(suite) -> []; +struct2_test(Config) -> + do_test(struct2_test, Config). + +struct_test(doc) -> ""; +struct_test(suite) -> []; +struct_test(Config) -> + do_test(struct_test, Config). + +term_sequence_test(doc) -> ""; +term_sequence_test(suite) -> []; +term_sequence_test(Config) -> + do_test(term_sequence_test, Config). + +term_struct_test(doc) -> ""; +term_struct_test(suite) -> []; +term_struct_test(Config) -> + do_test(term_struct_test, Config). + +term_test(doc) -> ""; +term_test(suite) -> []; +term_test(Config) -> + do_test(term_test, Config). + +typedef_test(doc) -> ""; +typedef_test(suite) -> []; +typedef_test(Config) -> + do_test(typedef_test, Config). + +unsigned_long_long_test(doc) -> ""; +unsigned_long_long_test(suite) -> []; +unsigned_long_long_test(Config) -> + do_test(unsigned_long_long_test, Config). + +unsigned_long_test(doc) -> ""; +unsigned_long_test(suite) -> []; +unsigned_long_test(Config) -> + do_test(unsigned_long_test, Config). + +unsigned_short_test(doc) -> ""; +unsigned_short_test(suite) -> []; +unsigned_short_test(Config) -> + do_test(unsigned_short_test, Config). + +void_test(doc) -> ""; +void_test(suite) -> []; +void_test(Config) -> + do_test(void_test, Config). + +wchar_test(doc) -> ""; +wchar_test(suite) -> []; +wchar_test(Config) -> + do_test(wchar_test, Config). + +wstring1_test(doc) -> ""; +wstring1_test(suite) -> []; +wstring1_test(Config) -> + do_test(wstring1_test, Config). + + +%% It is here that all tests really are done. +%% + +do_test(Case, Config) -> + %% Trap exits + process_flag(trap_exit, true), + %% Start the server + {ok, _Pid} = m_i:oe_create_link([], {local, ?ERLANG_SERVER_NAME}), + Node = atom_to_list(node()), + DataDir = ?config(data_dir, Config), + %% io:format("~p: data directory: ~p~n", [?MODULE, DataDir]), + Cookie = atom_to_list(erlang:get_cookie()), + %% Start C-client node as a port program. + Cmd = filename:join([DataDir, "c_client"]) ++ + " -this-node-name " ++ atom_to_list(?C_CLIENT_NODE_NAME) ++ + " -peer-node " ++ Node ++ + " -peer-process-name " ++ atom_to_list(?ERLANG_SERVER_NAME) ++ + " -cookie " ++ Cookie ++ + " -test-case " ++ atom_to_list(Case), + Port = open_port({spawn, Cmd}, [exit_status, eof, stderr_to_stdout]), + Res = wait_for_completion(Port), + %% Kill off node if there was timeout + case Res of + {error, timeout} -> + catch rpc:cast(?C_CLIENT_NODE_NAME, erlang, halt, [1]); + _ -> + ok + end, + process_flag(trap_exit, false), + catch m_i:stop(?ERLANG_SERVER_NAME), + ok = Res. + + +%% Wait for eof *and* exit status, but return if exit status indicates +%% an error, or we have been waiting more than PORT_TIMEOUT seconds. +%% +wait_for_completion(Port) -> + wait_for_completion(Port, 0). + +wait_for_completion(Port, N) when N < 2 -> + receive + {Port, {data, Bytes}} -> + %% Relay output + io:format("~s", [Bytes]), + wait_for_completion(Port, N); + {Port, {exit_status, 0}} -> + wait_for_completion(Port, N + 1); + {Port, {exit_status, Status}} -> + {error, Status}; + {Port, eof} -> + wait_for_completion(Port, N + 1); + {'EXIT', Port, Reason} -> + io:format("Port exited with reason: ~w~n", [Reason]), + wait_for_completion(Port, N); + {'EXIT', From, Reason} -> + io:format("Got unexpected exit: ~p~n", [{'EXIT', From, Reason}]), + wait_for_completion(Port, N) + after ?PORT_TIMEOUT -> + {error, timeout} + end; +wait_for_completion(_, _) -> + ok. + + + diff --git a/lib/ic/test/c_client_erl_server_SUITE_data/Makefile.src b/lib/ic/test/c_client_erl_server_SUITE_data/Makefile.src new file mode 100644 index 0000000000..6516e699bd --- /dev/null +++ b/lib/ic/test/c_client_erl_server_SUITE_data/Makefile.src @@ -0,0 +1,145 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2001-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# Makefile.src for c_client_erl_server test +# Note: This file *must* work for both Unix and Windows +# +# We use both `rm' (Unix) and `del' (Windows) for removing files, but +# with a `-' in front so that the error in not finding `rm' (`del') on +# Windows (Unix) is ignored. +# +# VxWorks? XXX +# + +.SUFFIXES: +.SUFFIXES: .c .h .erl .idl @obj@ .@EMULATOR@ + + +# Variables from ts: +# + +ERL_INCLUDE = @erl_include@ + +IC_INCLUDE_PATH = @ic_include_path@ +IC_LIB = @ic_libpath@@DS@@ic_lib@ + +ERL_INTERFACE_INCLUDE = @erl_interface_include@ +ERL_INTERFACE_LIB = @erl_interface_libpath@@DS@@erl_interface_lib@ +ERL_INTERFACE_EILIB = @erl_interface_libpath@@DS@@erl_interface_eilib@ +ERL_INTERFACE_THREADLIB = @erl_interface_threadlib@ +ERL_INTERFACE_SOCK_LIBS = @erl_interface_sock_libs@ + +CC = @CC@ +## XXX Should set warning flag with a DEBUG_FLAG +CFLAGS = @CFLAGS@ @DEFS@ -I@erl_include@ \ + -I@ic_include_path@ -I@erl_interface_include@ + +LD = @LD@ +LDFLAGS = @CROSSLDFLAGS@ +LIBS = $(IC_LIB) $(ERL_INTERFACE_LIB) $(ERL_INTERFACE_EILIB) \ + $(ERL_INTERFACE_THREADLIB) @LIBS@ $(ERL_INTERFACE_SOCK_LIBS) +ERLC = erlc + +# Generated C header files +GEN_H_FILES = \ + m.h \ + m_i.h \ + oe_c_erl_test.h + +# Generated C files +GEN_C_FILES = \ + m.c \ + m_i.c \ + oe_c_erl_test.c \ + oe_code_m_a.c \ + oe_code_m_arr1.c \ + oe_code_m_arr2.c \ + oe_code_m_arr3.c \ + oe_code_m_aseq.c \ + oe_code_m_b.c \ + oe_code_m_bseq.c \ + oe_code_m_dd.c \ + oe_code_m_dyn.c \ + oe_code_m_dyn_sl.c \ + oe_code_m_es.c \ + oe_code_m_et.c \ + oe_code_m_etseq.c \ + oe_code_m_fruit.c \ + oe_code_m_lseq.c \ + oe_code_m_s.c \ + oe_code_m_s_sl.c \ + oe_code_m_sarr3.c \ + oe_code_m_simple.c \ + oe_code_m_ssarr3.c \ + oe_code_m_sseq.c \ + oe_code_m_ssstr3.c \ + oe_code_m_sstr3.c \ + oe_code_m_str1.c \ + oe_code_m_str3.c \ + oe_code_m_strRec.c \ + oe_code_m_strRec_str5.c \ + oe_code_m_strRec_str7.c + +GEN_HRL_FILES = \ + m.hrl \ + m_i.hrl \ + oe_c_erl_test.hrl + +GEN_ERL_FILES = \ + m.erl \ + m_arr2.erl \ + m_arr3.erl \ + m_i.erl \ + m_str3.erl \ + oe_c_erl_test.erl + +C_FILES = $(GEN_C_FILES) c_client.c + +OBJS = $(C_FILES:.c=@obj@) + +PGMS = c_client@exe@ + +ERL_FILES = $(GEN_ERL_FILES) m_i_impl.erl + +EBINS = $(ERL_FILES:.erl=.@EMULATOR@) + + +all: $(PGMS) $(EBINS) + +clean: + -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + +$(PGMS): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_client}" c_erl_test.idl + +$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" c_erl_test.idl + +.c@obj@: + $(CC) -c -o $*@obj@ $(CFLAGS) $< + +.erl.@EMULATOR@: + $(ERLC) -I $(IC_INCLUDE_PATH) $< + diff --git a/lib/ic/test/c_client_erl_server_SUITE_data/c_client.c b/lib/ic/test/c_client_erl_server_SUITE_data/c_client.c new file mode 100644 index 0000000000..e4f9cfdece --- /dev/null +++ b/lib/ic/test/c_client_erl_server_SUITE_data/c_client.c @@ -0,0 +1,1760 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2001-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/* C-client for test of IC. + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef __WIN32__ +# include <unistd.h> +#endif + +#include <string.h> + +#ifdef __WIN32__ +# include <time.h> +# include <sys/timeb.h> +#elif defined VXWORKS +#include <time.h> +#include <sys/times.h> +#else +#include <sys/time.h> +#endif + +#include <ctype.h> + +#ifdef __WIN32__ +# include <winsock2.h> +# include <windows.h> +#else +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# include <netdb.h> +#endif + +#include "ei.h" +#include "erl_interface.h" +#include "m_i.h" + +#define HOSTNAMESZ 256 +#define NODENAMESZ 512 + +#define INBUFSZ 10 +#define OUTBUFSZ 0 + +#define MAXTRIES 5 + +#define CHECK_EXCEPTION(x) \ + if ((x)->_major != CORBA_NO_EXCEPTION) { \ + fprintf(stderr,"\n\nException: %s\n\n", \ + (char *)CORBA_exception_value((x))); \ + CORBA_exception_free((x)); \ + return -1; \ + } \ + +/* XXX Should free things here too! */ +#define RETURN_IF_OK(x) \ + if ((x)) {\ + fprintf(stdout, "ok\n");\ + return 0;\ + }\ + +#define cmp_str(x,y) (!strcmp((x),(y))) +#define cmp_wstr(x,y) (!ic_wstrcmp((x),(y))) + +typedef CORBA_Environment IC_Env; + +typedef int (*TestFunc)(IC_Env *); +typedef struct { + char *name; + TestFunc func; +} TestCase; + +static char longtext[] = +"Introduction The IC application is an IDL compiler implemented in Erlang." +" The IDL compiler generates client stubs and server skeletons." +" Several back-ends are supported, and they fall into three main groups." +" For more details on IC compiler options consult the ic(3) manual page." +" Argument passing cases 1 Caller allocates all necessary storage," +" except that which may be encapsulated and managed within the parameter itself." +" 2 The caller allocates a pointer and passes it by reference to the callee." +" The callee sets the pointer to point to a valid instance of the parameter's type." +" The caller is responsible for releasing the returned storage." +" Following completion of a request, the caller is not allowed to modify any values" +" in the returned storage. To do so the caller must first copy the returned instance" +" into a new instance, then modify the new instance. 3 The caller allocates a" +" pointer to an array slice which has all the same dimensions of the original" +" array except the first, and passes it by reference to the callee. The callee sets" +" the pointer to point to a valid instance of the array. The caller is responsible for" +" releasing the returned storage. Following completion of a request, the caller is not" +" allowed to modify any values in the returned storage. To do so the caller must first" +" copy the returned instance into a new instance, then modify the new instance." +" Generated Files Two files will be generated for each scope. One set of files will be" +" generated for each module and each interface scope. An extra set is generated for" +" those definitions at top level scope. One of the files is a header file(.h), and the" +" other file is a C source code file (.c). In addition to these files a number of C" +" source files will be generated for type encodings, they are named according to the " +"following template: oe_code_<type>.c."; +static char this_node[NODENAMESZ + 1]; +static char *progname; + +/* Test function prototypes */ + +static int void_test(IC_Env *env); +static int long_test(IC_Env *env); +static int long_long_test(IC_Env *env); +static int unsigned_short_test(IC_Env *env); +static int unsigned_long_test(IC_Env *env); +static int unsigned_long_long_test(IC_Env *env); +static int double_test(IC_Env *env); +static int char_test(IC_Env *env); +static int wchar_test(IC_Env *env); +static int octet_test(IC_Env *env); +static int bool_test(IC_Env *env); +static int struct_test(IC_Env *env); +static int struct2_test(IC_Env *env); +static int seq1_test(IC_Env *env); +static int seq2_test(IC_Env *env); +static int seq3_test(IC_Env *env); +static int seq4_test(IC_Env *env); +static int seq5_test(IC_Env *env); +static int array1_test(IC_Env *env); +static int array2_test(IC_Env *env); +static int enum_test(IC_Env *env); +static int string1_test(IC_Env *env); +static int string2_test(IC_Env *env); +static int string3_test(IC_Env *env); +static int string4_test(IC_Env *env); +static int pid_test(IC_Env *env); +static int port_test(IC_Env *env); +static int ref_test(IC_Env *env); +static int term_test(IC_Env *env); +static int typedef_test(IC_Env *env); +static int inline_sequence_test(IC_Env *env); +static int term_sequence_test(IC_Env *env); +static int term_struct_test(IC_Env *env); +static int wstring1_test(IC_Env *env); + +static TestCase test_cases[] = { + {"void_test", void_test}, + {"long_test", long_test}, + {"long_long_test", long_long_test}, + {"unsigned_short_test", unsigned_short_test}, + {"unsigned_long_test", unsigned_long_test}, + {"unsigned_long_long_test", unsigned_long_long_test}, + {"double_test", double_test}, + {"char_test", char_test}, + {"wchar_test", wchar_test}, + {"octet_test", octet_test}, + {"bool_test", bool_test}, + {"struct_test", struct_test}, + {"struct2_test", struct2_test}, + {"seq1_test", seq1_test}, + {"seq2_test", seq2_test}, + {"seq3_test", seq3_test}, + {"seq4_test", seq4_test}, + {"seq5_test", seq5_test}, + {"array1_test", array1_test}, + {"array2_test", array2_test}, + {"enum_test", enum_test}, + {"string1_test", string1_test}, + {"string2_test", string2_test}, + {"string3_test", string3_test}, + {"string4_test", string4_test}, + {"pid_test", pid_test}, + {"port_test", port_test}, + {"ref_test", ref_test}, + {"term_test", term_test}, + {"typedef_test", typedef_test}, + {"inline_sequence_test", inline_sequence_test}, + {"term_sequence_test", term_sequence_test}, + {"term_struct_test", term_struct_test}, + {"wstring1_test", wstring1_test}, + {"", NULL} +}; + +/* Other prototypes */ +static int cmp_aseq(m_aseq *a1, m_aseq *a2); +static int cmp_a(m_a *a1, m_a *a2); +static int cmp_bseq(m_bseq *b1, m_bseq *b2); +static int cmp_b(m_b *b1, m_b *b2); +static int cmp_lseq(m_lseq *b1, m_lseq *b2); +static int cmp_etseq(m_etseq *b1, m_etseq *b2); +static int cmp_et(m_et* b1, m_et *b2); +static int cmp_es(m_es *b1, m_es *b2); +static int cmp_arr1(m_arr1 b1, m_arr1 b2); +static int cmp_dd(m_dd b1, m_dd b2); +static int cmp_strRec(m_strRec *b1, m_strRec *b2); +static int cmp_sseq(m_sseq *b1, m_sseq *b2); +static int cmp_pid(erlang_pid *p1, erlang_pid *p2); +static int cmp_port(erlang_port *p1, erlang_port *p2); +static int cmp_ref(erlang_ref *p1, erlang_ref *p2); +static int cmp_s(m_s *b1, m_s *b2); +static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2); +static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2); +static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2); +static int cmp_arr3(m_arr3 b1, m_arr3 b2); + +static void print_aseq(m_aseq *a); +static void print_a(m_a *a); +static void print_bseq(m_bseq *b); +static void print_lseq(m_lseq *b); +static void print_b(m_b *b); +static void print_etseq(m_etseq *b); +static void print_et(m_et* b); +static void print_es(m_es *b); +static void print_arr1(long a[500]); +static void print_dd(long a[2][3]); +static void print_strRec(m_strRec* sr); +static void print_sseq(m_sseq *b); +static void print_pid(erlang_pid *p); +static void print_port(erlang_port *p); +static void print_ref(erlang_ref *p); +static void print_term(ETERM *t); +static void print_s(m_s *p); +static void print_ssstr3(m_ssstr3 *b1); +static void print_ssarr3(m_ssarr3 *b1); +static void print_sarr3(m_sarr3 *b1); +static void print_arr3(m_arr3 b1); +static void print_wstr(CORBA_wchar *ws); + +static void free_etseq_buf(m_etseq *b); +static void free_et(m_et* b); + +#ifdef __WIN32__ +typedef struct { + long tv_sec; + long tv_usec; +} MyTimeval; +#else +typedef struct timeval MyTimeval; +#endif +static void my_gettimeofday(MyTimeval *tv); +static void showtime(MyTimeval *start, MyTimeval *stop); +static void usage(void); +static void done(int r); + + + +/* main */ + +#ifdef VXWORKS +int client(int argc, char **argv) +#else +int main(int argc, char **argv) +#endif +{ + struct hostent *hp; + erlang_pid pid; + MyTimeval start, stop; + int i, fd, ires, tres; + IC_Env *env; + int tries = 0; + char *this_node_name = NULL; + char *peer_node = NULL; + char *peer_process_name = NULL; + char *cookie = NULL; + char host[HOSTNAMESZ + 1]; + TestFunc test_func = NULL; + TestCase *test_case; + char *test_case_name = NULL; + +#ifdef __WIN32__ + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD(2, 0); + + if (WSAStartup(wVersionRequested, &wsaData) != 0) { + fprintf(stderr, "Could not load winsock2 v2.0 compatible DLL"); + exit(1); + } +#endif + + progname = argv[0]; + host[HOSTNAMESZ] = '\0'; + if (gethostname(host, HOSTNAMESZ) < 0) { + fprintf(stderr, "Can't find own hostname\n"); + done(1); + } + if ((hp = gethostbyname(host)) == 0) { + fprintf(stderr, "Can't get ip address for host %s\n", host); + done(1); + } + for (i = 1; i < argc; i++) { + if (cmp_str(argv[i], "-help")) { + usage(); + done(0); + } else if (cmp_str(argv[i], "-this-node-name")) { + i++; + this_node_name = argv[i]; + } else if (cmp_str(argv[i], "-peer-node")) { + i++; + peer_node = argv[i]; + } else if (cmp_str(argv[i], "-peer-process-name")) { + i++; + peer_process_name = argv[i]; + } else if (cmp_str(argv[i], "-cookie")) { + i++; + cookie = argv[i]; + } else if (cmp_str(argv[i], "-test-case")) { + i++; + test_case_name = argv[i]; + } else { + fprintf(stderr, "Error : invalid argument \"%s\"\n", argv[i]); + usage(); + done(1); + } + } + + if (this_node_name == NULL || peer_node == NULL || test_case_name == NULL + || peer_process_name == NULL || cookie == NULL) { + fprintf(stderr, "Error: missing option\n"); + usage(); + done(1); + } + + test_case = test_cases; + while (test_case->func) { + if (cmp_str(test_case->name, test_case_name)) { + test_func = test_case->func; + break; + } + test_case++; + } + if (test_func == NULL) { + fprintf(stderr, "Error: illegal test case: \"%s\"\n", test_case_name); + done(1); + } + + /* Behead hostname at first dot */ + for (i=0; host[i] != '\0'; i++) { + if (host[i] == '.') { host[i] = '\0'; break; } + } + sprintf(this_node, "%s@%s", this_node_name, host); + fprintf(stderr, "c_client: this node: \"%s\"\n", this_node); + fprintf(stderr, "c_client: peer node: \"%s\"\n", peer_node); + fprintf(stderr, "c_client: test case: \"%s\"\n", test_case_name); + + fprintf(stderr, "c_client: starting\n"); + + /* initialize erl_interface */ + erl_init(NULL, 0); + + for (tries = 0; tries < MAXTRIES; tries++) { + + /* connect to erlang node */ + + ires = erl_connect_xinit(host, this_node_name, this_node, + (struct in_addr *)*hp->h_addr_list, + cookie, 0); + + fprintf(stderr, "c_client: erl_connect_xinit(): %d\n", ires); + + fd = erl_connect(peer_node); + fprintf(stderr, "c_client: erl_connect(): %d\n", fd); + + if (fd >= 0) + break; + fprintf(stderr, "c_client: cannot connect, retrying\n"); + } + if (fd < 0) { + fprintf(stderr, "c_client: cannot connect, exiting\n"); + done(1); + } + env = CORBA_Environment_alloc(INBUFSZ, OUTBUFSZ); + env->_fd = fd; + strcpy(env->_regname, peer_process_name); + env->_to_pid = NULL; + env->_from_pid = &pid; + + strcpy(pid.node, this_node); + pid.num = fd; + pid.serial = 0; + pid.creation = 0; + + my_gettimeofday(&start); + tres = test_func(env); /* Call test case */ + my_gettimeofday(&stop); + showtime(&start, &stop); + erl_close_connection(fd); + + printf("c_client: env->_inbuf before : %d\n", INBUFSZ); + printf("c_client: env->_outbuf before : %d\n", OUTBUFSZ); + printf("c_client: env->_inbuf after : %d\n", env->_inbufsz); + printf("c_client: env->_outbuf after : %d\n", env->_outbufsz); + + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + done(tres); +} + +static void usage() +{ + fprintf(stderr, "Usage: %s [-help] -this-node-name <name> " + "-peer-node <nodename> -peer-process-name <name> " + "-cookie <cookie> -test-case <test case name>\n", progname); + fprintf(stderr, "Example:\n %s -this-node-name kalle " + "-peer-node olle@home -peer-process-name idltest " + "-cookie oa678er -test-case octet_test\n", progname); +} + +static void done(int r) +{ +#ifdef __WIN32__ + WSACleanup(); +#endif + exit(r); +} + + +/* TESTS */ + +static int void_test(IC_Env *env) +{ + fprintf(stdout, "\n======== m_i_void test ======\n\n"); + m_i_void_test(NULL,env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(1); +} + +static int long_test(IC_Env *env) +{ + long l = 4711, lo, lr; + + fprintf(stdout, "\n======== m_i_long test ======\n\n"); + lr = m_i_long_test(NULL, l, &lo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(l == lo && l == lr); + if (l != lo) + fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n", l, lo); + if (l != lr) + fprintf(stdout, " result error, sent: %ld, got: %ld\n", l, lr); + return -1; +} + +static int long_long_test(IC_Env *env) +{ + CORBA_long_long ll = 4711, llo, llr; + + fprintf(stdout, "\n======== m_i_longlong test ======\n\n"); + llr = m_i_longlong_test(NULL, ll, &llo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ll == llo && ll == llr); + if (ll != llo) + fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n", + ll, llo); + if (ll != llr) + fprintf(stdout, " result error, sent: %ld, got: %ld\n", ll, llr); + return -1; +} + +static int unsigned_short_test(IC_Env *env) +{ + unsigned short x, y = 2, z; + + fprintf(stdout, "\n======== m_i_ushort test ======\n\n"); + x = m_i_ushort_test(NULL, y, &z, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(y == z && y == x); + if (y != z) + fprintf(stdout, " out parameter error, sent: %d, got: %d\n", y, z); + if (y != x) + fprintf(stdout, " result error, sent: %d, got: %d\n", y, x); + return -1; +} + + +static int unsigned_long_test(IC_Env *env) +{ + unsigned long ul = 5050, ulo, ulr; + + fprintf(stdout, "\n======== m_i_ulong test ======\n\n"); + ulr = m_i_ulong_test(NULL, ul, &ulo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ul == ulo && ul == ulr); + if (ul != ulo) + fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n", + ul, ulo); + if (ul != ulr) + fprintf(stdout, " result error, sent: %lu, got: %lu\n", ul, ulr); + return -1; +} + +/* + * Note: CORBA_unsigned_long_long is in fact a plain long. + */ +static int unsigned_long_long_test(IC_Env *env) +{ + CORBA_unsigned_long_long ull = 5050, ullo, ullr; + + fprintf(stdout, "\n======== m_i_ulonglong test ======\n\n"); + ullr = m_i_ulonglong_test(NULL, ull, &ullo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ull == ullo && ull == ullr); + if (ull != ullo) + fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n", + ull, ullo); + if (ull != ullr) + fprintf(stdout, " result error, sent: %lu, got: %lu\n", + ull, ullr); + return -1; +} + +static int double_test(IC_Env *env) +{ + double d = 12.1212, db, dr; + + fprintf(stdout, "\n======== m_i_double test ======\n\n"); + dr = m_i_double_test(NULL, d, &db, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(d == db && d == dr); + if (d != db) + fprintf(stdout, " out parameter error, sent: %f, got: %f\n", d, db); + if (d != dr) + fprintf(stdout, " result error, sent: %f, got: %f\n", d, dr); + return -1; +} + +static int char_test(IC_Env *env) +{ + char c = 'g', co, cr; + + /* char test */ + fprintf(stdout, "\n======== m_i_char test ======\n\n"); + cr = m_i_char_test(NULL, c, &co, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(c == co && c == cr); + if (c !=co) + fprintf(stdout, " out parameter error, sent: %c, got: %c\n", c, co); + if (c != cr) + fprintf(stdout, " result error, sent: %c, got: %c\n", c, cr); + return -1; +} + +static int wchar_test(IC_Env *env) +{ + CORBA_wchar wc = 103, wco, wcr; + + fprintf(stdout, "\n======== m_i_wchar test ======\n\n"); + wcr = m_i_wchar_test(NULL, wc, &wco, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(wc == wco && wc == wcr); + if (wc != wco) + fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n", + wc, wco); + if (wc != wcr) + fprintf(stdout, " result error, sent: %lu, got: %lu\n", + wc, wcr); + return -1; +} + +static int octet_test(IC_Env *env) +{ + char o ='r', oo, or; + + fprintf(stdout, "\n======== m_i_octet test ======\n\n"); + or = m_i_octet_test(NULL, o, &oo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(o == oo && o == or); + if (o != oo) + fprintf(stdout, " out parameter error, sent: %c, got: %c\n", o, oo); + if (o != or) + fprintf(stdout, " result error, sent: %c, got: %c\n", o, or); + return -1; +} + +static int bool_test(IC_Env *env) +{ + unsigned char i = 0, io, ir; + + fprintf(stdout, "\n======== m_i_bool test ======\n\n"); + ir = m_i_bool_test(NULL, i, &io, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(i == io && i == ir); + if (i != io) + fprintf(stdout, " out parameter error, sent: %d, got: %d\n", i, io); + if (i != ir) + fprintf(stdout, " result error, sent: %d, got: %d\n", i, ir); + return -1; +} + +static int struct_test(IC_Env *env) +{ + m_b b = {4711, 'a'}, bo, br; + + fprintf(stdout, "\n======== m_i_struct test ======\n\n"); + br = m_i_struct_test(NULL, &b, &bo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_b(&b, &bo) && cmp_b(&b, &br)); + if (!cmp_b(&b, &bo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_b(&b); + fprintf(stdout, " got:\n"); + print_b(&bo); + fprintf(stdout, "\n"); + } + if (!cmp_b(&b, &br)) { + fprintf(stdout, " result error, sent:\n"); + print_b(&b); + fprintf(stdout, " got:\n"); + print_b(&br); + fprintf(stdout, "\n"); + } + return -1; +} + +static int struct2_test(IC_Env *env) +{ + m_es esi = {m_peach, 5050}, eso, esr; + + fprintf(stdout, "\n======== m_i_struct2 test ======\n\n"); + esr = m_i_struct2_test(NULL, &esi, &eso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_es(&esi, &eso) && cmp_es(&esi, &esr)); + if (!cmp_es(&esi, &eso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_es(&esi); + fprintf(stdout, " got:\n"); + print_es(&eso); + fprintf(stdout, "\n"); + } + if (!cmp_es(&esi, &esr)) { + fprintf(stdout, " result error, sent:\n"); + print_es(&esi); + fprintf(stdout, " got:\n"); + print_es(&esr); + fprintf(stdout, "\n"); + } + return -1; +} + + +static int seq1_test(IC_Env *env) +{ + m_bseq bs, *bso, *bsr; + + m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}}; + bs._length = 3; + bs._buffer = ba; + + fprintf(stdout, "\n======== m_i_seq1 test ======\n\n"); + bsr = m_i_seq1_test(NULL, &bs, &bso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_bseq(&bs, bso) && cmp_bseq(&bs, bsr)); + if (!cmp_bseq(&bs, bso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_bseq(&bs); + fprintf(stdout, " got:\n"); + print_bseq(bso); + fprintf(stdout, "\n"); + } + if (!cmp_bseq(&bs, bsr)) { + fprintf(stdout, " result error, sent:\n"); + print_bseq(&bs); + fprintf(stdout, " got:\n"); + print_bseq(bsr); + fprintf(stdout, "\n"); + } + CORBA_free(bso); + CORBA_free(bsr); + return -1; +} + +static int seq2_test(IC_Env *env) +{ + m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}}; + m_a a; + m_a aa[2]; + m_aseq as, *aso, *asr; + + a.l = 9999; + a.y._length = 3; + a.y._buffer = ba; + a.d = 66.89898989; + + aa[0] = a; + aa[1] = a; + as._length = 2; + as._buffer = aa; + + fprintf(stdout, "\n======== m_i_seq2 test ======\n\n"); + asr = m_i_seq2_test(NULL, &as, &aso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_aseq(&as, aso) && cmp_aseq(&as, asr)); + if (!cmp_aseq(&as, aso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_aseq(&as); + fprintf(stdout, " got:\n"); + print_aseq(aso); + fprintf(stdout, "\n"); + } + if (!cmp_aseq(&as, asr)) { + fprintf(stdout, " result error, sent:\n"); + print_aseq(&as); + fprintf(stdout, " got:\n"); + print_aseq(asr); + fprintf(stdout, "\n"); + } + CORBA_free(aso); + CORBA_free(asr); + return -1; +} + +static int seq3_test(IC_Env *env) +{ + m_lseq lsi, *lso, *lsr; + long al[500]; + int i=0; + + for (i = 0; i < 500; i++) + al[i]=i; + lsi._length = 500; + lsi._buffer = al; + + fprintf(stdout, "\n======== m_i_seq3 test ======\n\n"); + lsr = m_i_seq3_test(NULL, &lsi, &lso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_lseq(&lsi, lso) && cmp_lseq(&lsi, lsr)); + if (!cmp_lseq(&lsi, lso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_lseq(&lsi); + fprintf(stdout, " got:\n"); + print_lseq(lso); + fprintf(stdout, "\n"); + } + if (!cmp_lseq(&lsi, lsr)) { + fprintf(stdout, " result error, sent:\n"); + print_lseq(&lsi); + fprintf(stdout, " got:\n"); + print_lseq(lsr); + fprintf(stdout, "\n"); + } + CORBA_free(lso); + CORBA_free(lsr); + return -1; +} + +static int seq4_test(IC_Env *env) +{ + char *stra0[3] = {"a", "long", "time"}; + char *stra1[3] = {"ago", "there", "was"}; + char *stra2[3] = {"a", "buggy", "compiler"}; + m_sstr3 str3s[3] = {{3, 3, stra0}, {3, 3, stra1}, {3, 3, stra2}}; + m_ssstr3 str3ssi = {3, 3, str3s}; + m_ssstr3 *str3sso, *str3ssr; + + fprintf(stdout, "\n======== m_i_seq4 test ======\n\n"); + str3ssr = m_i_seq4_test(NULL, &str3ssi, &str3sso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_ssstr3(&str3ssi, str3sso) && + cmp_ssstr3(&str3ssi, str3ssr)); + if (!cmp_ssstr3(&str3ssi, str3sso)){ + fprintf(stdout, " out parameter error, sent:\n"); + print_ssstr3(&str3ssi); + fprintf(stdout, " got:\n"); + print_ssstr3(str3sso); + fprintf(stdout, "\n"); + } + if (!cmp_ssstr3(&str3ssi, str3ssr)) { + fprintf(stdout, " result error, sent:\n"); + print_ssstr3(&str3ssi); + fprintf(stdout, " got:\n"); + print_ssstr3(str3ssr); + fprintf(stdout, "\n"); + } + CORBA_free(str3sso); + CORBA_free(str3ssr); + return -1; +} + +static int seq5_test(IC_Env *env) +{ + m_arr3 arr3a[3] = { + {4711, 18931947, 3}, + {4711, 18931947, 3}, + {4711, 18931947, 3}}; + m_sarr3 arr3sa[3] = {{3, 3, arr3a}, {3, 3, arr3a}, {3, 3, arr3a}}; + m_ssarr3 arr3ssi = {3, 3, arr3sa}; + m_ssarr3 *arr3sso; + m_ssarr3 *arr3ssr; + + fprintf(stdout, "\n======== m_i_seq5 test ======\n\n"); + arr3ssr = m_i_seq5_test(NULL, &arr3ssi, &arr3sso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_ssarr3(&arr3ssi, arr3sso) && + cmp_ssarr3(&arr3ssi, arr3ssr)); + if (!cmp_ssarr3(&arr3ssi, arr3sso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_ssarr3(&arr3ssi); + fprintf(stdout, " got:\n"); + print_ssarr3(arr3sso); + fprintf(stdout, "\n"); + } + if (!cmp_ssarr3(&arr3ssi, arr3ssr)) { + fprintf(stdout, " result error, sent:\n"); + print_ssarr3(&arr3ssi); + fprintf(stdout, " got:\n"); + print_ssarr3(arr3ssr); + fprintf(stdout, "\n"); + } + CORBA_free(arr3sso); + CORBA_free(arr3ssr); + return -1; +} + +static int array1_test(IC_Env *env) +{ + int i; + long al[500]; + m_arr1 alo; + m_arr1_slice* alr; + + for (i = 0; i < 500; i++) + al[i]=i; + + fprintf(stdout, "\n======== m_i_array1 test ======\n\n"); + alr = m_i_array1_test(NULL, al, alo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_arr1(al, alo) && cmp_arr1(al, alr)); + if (!cmp_arr1(al, alo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_arr1(al); + fprintf(stdout, " got:\n"); + print_arr1(alo); + fprintf(stdout, "\n"); + } + if (!cmp_arr1(al,alr)) { + fprintf(stdout, " result error, sent:\n"); + print_arr1(al); + fprintf(stdout, " got:\n"); + print_arr1(alr); + fprintf(stdout, "\n"); + } + free(alo); + free(alr); + return -1; +} + +static int array2_test(IC_Env *env) +{ + long dl[2][3] = {{11, 2, 7}, {22, 8 ,13}}; + m_dd dlo; + m_dd_slice* dlr; + + fprintf(stdout, "\n======== m_i_array2 test ======\n\n"); + dlr = m_i_array2_test(NULL, dl, dlo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_dd(dl,dlo) && cmp_dd(dl,dlr)); + if (!cmp_dd(dl,dlo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_dd(dl); + fprintf(stdout, " got:\n"); + print_dd(dlo); + fprintf(stdout, "\n"); + } + if (!cmp_dd(dl,dlr)) { + fprintf(stdout, " result error, sent:\n"); + print_dd(dl); + fprintf(stdout, " got:\n"); + print_dd(dlr); + fprintf(stdout, "\n"); + } + free(*dlr); + return -1; +} + +static int enum_test(IC_Env *env) +{ + m_fruit ei = m_banana, eo, er; + + fprintf(stdout, "\n======== m_i_enum test ======\n\n"); + er = m_i_enum_test(NULL, ei, &eo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ei == eo && ei == er); + if (ei != eo) + fprintf(stdout, " out parameter error, sent: %d, got: %d\n", ei, eo); + if (ei != er) + fprintf(stdout, " result error, sent: %d, got: %d\n", ei, er); + return -1; +} + +static int string1_test(IC_Env *env) +{ + char* si = longtext; + char* so; + char* sr; + + fprintf(stdout, "\n======== m_i_string1 test ======\n\n"); + sr = m_i_string1_test(NULL, si, &so, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, sr)); + if (!cmp_str(si, so)) + fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so); + if (!cmp_str(si, sr)) + fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr); + CORBA_free(so); + CORBA_free(sr); + return -1; +} + +static int string2_test(IC_Env *env) +{ + char* sa[3] = {"hello", "foo", "bar"}; + m_sseq ssi = {3, 3, sa}; + m_sseq *sso, *ssr; + + fprintf(stdout, "\n======== m_i_string2 test ======\n\n"); + ssr = m_i_string2_test(NULL, &ssi, &sso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_sseq(&ssi, sso) && cmp_sseq(&ssi, sso)); + if (!cmp_sseq(&ssi, sso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_sseq(&ssi); + fprintf(stdout, "got:\n"); + print_sseq(sso); + } + if (!cmp_sseq(&ssi, ssr)) { + fprintf(stdout, " result error, sent:\n"); + print_sseq(&ssi); + fprintf(stdout, "got:\n"); + print_sseq(ssr); + } + CORBA_free(sso); + CORBA_free(ssr); + return -1; +} + +static int string3_test(IC_Env *env) +{ + char* si = longtext; + char* so; + char* sr; + + fprintf(stdout, "\n======== m_i_string3 test ======\n\n"); + sr = m_i_string3_test(NULL, si, &so, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, so)); + if (!cmp_str(si, so)) + fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so); + if (!cmp_str(si, sr)) + fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr); + CORBA_free(so); + CORBA_free(sr); + return -1; +} + +static int string4_test(IC_Env *env) +{ + char as1[100] = "a string", as2[200] = "help", as3[200] = "hello there"; + m_strRec stri = { 1, /* dd */ + as1, /* str4 */ + {{'a', 'k'}, {'z', 'g'}, {'n', 'q'}}, /* str7 */ + {3, 3, "buf"}, /* str5 */ + as2, /* str6 */ + {'m', 'f', 'o'}, /* str8 */ + as3, /* str9 */ + {3, 3, "stu"} /* str10 */ + }; + m_strRec *stro, *strr; + + fprintf(stdout, "\n======== m_i_string4 test ======\n\n"); + strr = m_i_string4_test(NULL, &stri, &stro, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_strRec(&stri,stro) && cmp_strRec(&stri,strr)); + if (!cmp_strRec(&stri,stro)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_strRec(&stri); + fprintf(stdout, " got:\n"); + print_strRec(stro); + fprintf(stdout, "\n"); + } + if (!cmp_strRec(&stri,strr)) { + fprintf(stdout, " result error, sent:\n"); + print_strRec(&stri); + fprintf(stdout, " got:\n"); + print_strRec(strr); + fprintf(stdout, "\n"); + } + CORBA_free(stro); + CORBA_free(strr); + return -1; +} + + +static int pid_test(IC_Env *env) +{ + erlang_pid pid = {"", 7, 0, 0}, pido, pidr; + + strcpy(pid.node, this_node), /* this currently running node */ + fprintf(stdout, "\n======== m_i_pid test ======\n\n"); + pidr = m_i_pid_test(NULL, &pid, &pido, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_pid(&pid, &pido) && cmp_pid(&pid, &pidr)); + if (!cmp_pid(&pid, &pido)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_pid(&pid); + fprintf(stdout, "got:\n"); + print_pid(&pido); + } + if (!cmp_pid(&pid, &pidr)) { + fprintf(stdout, " result error, sent:\n"); + print_pid(&pid); + fprintf(stdout, "got:\n"); + print_pid(&pidr); + } + return -1; +} + +static int port_test(IC_Env *env) +{ + erlang_port porti = {"node", 5, 1}, porto, portr; + + fprintf(stdout, "\n======== m_i_port test ======\n\n"); + portr = m_i_port_test(NULL, &porti, &porto, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_port(&porti, &porto) && cmp_port(&porti, &portr)); + if (!cmp_port(&porti, &porto)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_port(&porti); + fprintf(stdout, "got:\n"); + print_port(&porto); + } + if (!cmp_port(&porti, &portr)) { + fprintf(stdout, " result error, sent:\n"); + print_port(&porti); + fprintf(stdout, "got:\n"); + print_port(&portr); + } + return -1; +} + +static int ref_test(IC_Env *env) +{ + erlang_ref refi = { "node1", 3, {1, 2, 3}, 1}, + refo, refr; + + fprintf(stdout, "\n======== m_i_ref test ======\n\n"); + refr = m_i_ref_test(NULL, &refi, &refo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_ref(&refi, &refo) && cmp_ref(&refi, &refr)); + if (!cmp_ref(&refi, &refo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_ref(&refi); + fprintf(stdout, "got:\n"); + print_ref(&refo); + } + if (!cmp_ref(&refi, &refr)) { + fprintf(stdout, " result error, sent:\n"); + print_ref(&refi); + fprintf(stdout, "got:\n"); + print_ref(&refr); + } + return -1; +} + +static int term_test(IC_Env *env) +{ + ETERM *ti, *to, *tr; + + ti = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"); + + fprintf(stdout, "\n======== m_i_term test ======\n\n"); + tr = m_i_term_test(NULL, ti, &to, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(erl_match(ti, to) && erl_match(ti, tr)); + if (!erl_match(ti, to)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_term(ti); + fprintf(stdout, "got:\n"); + print_term(to); + } + if (!erl_match(ti, tr)) { + fprintf(stdout, " result error, sent:\n"); + print_term(ti); + fprintf(stdout, "got:\n"); + print_term(tr); + } + erl_free_term(ti); + erl_free_term(to); + erl_free_term(tr); + return -1; +} + +static int typedef_test(IC_Env *env) +{ + m_banan mbi, mbo; /* erlang_port */ + m_apa mai; /* ETERM* */ + m_apa mao = NULL; + long tl; + + strcpy(mbi.node,"node"); + mbi.id = 15; + mbi.creation = 1; + + fprintf(stdout, "\n======== m_i_typedef test ======\n\n"); + mai = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"); + tl = m_i_typedef_test(NULL, mai, &mbi, &mao, &mbo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(erl_match(mai, mao) && cmp_port(&mbi, &mbo) && tl == 4711); + if (!erl_match(mai, mao)) { + fprintf(stdout, " out parameter error (term), sent:\n"); + print_term(mai); + fprintf(stdout, "got:\n"); + print_term(mao); + } + if (!cmp_port(&mbi, &mbo)) { + fprintf(stdout, " out parameter error (port), sent:\n"); + print_port(&mbi); + fprintf(stdout, "got:\n"); + print_port(&mbo); + } + if (tl != 4711) { + fprintf(stdout, " result error, sent: 4711, got %ld\n", tl); + } + erl_free_term(mai); + erl_free_term(mao); + return -1; +} + +static int inline_sequence_test(IC_Env *env) +{ + int i; + long al[500]; + m_s isi = {4711, {500, 10, al}}, + *iso, *isr; + + for (i = 0; i < 500; i++) + al[i]=i; + fprintf(stdout, "\n======== m_i_inline_sequence test ======\n\n"); + isr = m_i_inline_sequence_test(NULL, &isi, &iso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_s(&isi, iso) && cmp_s(&isi, isr)); + if (!cmp_s(&isi, iso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_s(&isi); + fprintf(stdout, "got:\n"); + print_s(iso); + } + if (!cmp_s(&isi, isr)) { + fprintf(stdout, " result error, sent:\n"); + print_s(&isi); + fprintf(stdout, "got:\n"); + print_s(isr); + } + CORBA_free(iso); + CORBA_free(isr); + return -1; +} + +static int term_sequence_test(IC_Env *env) +{ + ETERM* et_array[4] = { + erl_format("[{apa, 1, 23}, \"string\", {1.23, 45}]"), + erl_format("[{banan, 1, 23}, \"string\", {1.23, 45}]"), + erl_format("[{apelsin, 1, 23}, \"string\", {1.23, 45}]"), + erl_format("[{mango, 1, 23}, \"string\", {1.23, 45}]")}; + m_etseq etsi = {4, 4, et_array}, *etso, *etsr; + + fprintf(stdout, "\n======== m_i_term_sequence test ======\n\n"); + etsr = m_i_term_sequence_test(NULL, &etsi, &etso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_etseq(&etsi, etso) && cmp_etseq(&etsi, etsr)); + if (!cmp_etseq(&etsi, etso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_etseq(&etsi); + fprintf(stdout, "got:\n"); + print_etseq(etso); + } + if (!cmp_etseq(&etsi, etsr)) { + fprintf(stdout, " result error, sent:\n"); + print_etseq(&etsi); + fprintf(stdout, "got:\n"); + print_etseq(etsr); + } + free_etseq_buf(&etsi); + free_etseq_buf(etso); + free_etseq_buf(etsr); + CORBA_free(etso); + CORBA_free(etsr); + return -1; +} + +static int term_struct_test(IC_Env *env) +{ + m_et eti = { erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"), + 121212 }; + m_et eto, etr; + + fprintf(stdout, "\n======== m_i_term_struct test ======\n\n"); + etr = m_i_term_struct_test(NULL, &eti, &eto, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_et(&eti, &eto) && cmp_et(&eti, &etr)); + if (!cmp_et(&eti, &eto)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_et(&eti); + fprintf(stdout, "got:\n"); + print_et(&eto); + } + if (!cmp_et(&eti, &etr)) { + fprintf(stdout, " result error, sent:\n"); + print_et(&eti); + fprintf(stdout, "got:\n"); + print_et(&etr); + } + free_et(&eti); + free_et(&eto); + free_et(&etr); + return -1; +} + +static int wstring1_test(IC_Env *env) +{ + CORBA_wchar wsi[] = {100, 101, 102, 103, 104, 0}, *wso, *wsr; + + fprintf(stdout, "\n======== m_i_wstring1 test ======\n\n"); + wsr = m_i_wstring1_test(NULL, wsi, &wso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_wstr(wsi, wso) && cmp_wstr(wsi, wsr)); + if (!cmp_wstr(wsi, wso)) { + fprintf(stdout, " out parameter error, sent: \n"); + print_wstr(wsi); + fprintf(stdout, "got:\n"); + print_wstr(wso); + } + if (!cmp_wstr(wsi, wsr)) { + fprintf(stdout, " result error, sent: \n"); + print_wstr(wsi); + fprintf(stdout, "got:\n"); + print_wstr(wsr); + } + CORBA_free(wso); + CORBA_free(wsr); + return -1; +} + +/* Compare functions */ +static int cmp_aseq(m_aseq *a1, m_aseq *a2) +{ + int i; + + if (a1->_length != a2->_length) + return 0; + for (i = 0; i < a1->_length; i++) + if (cmp_a(&(a1->_buffer[i]), &(a2->_buffer[i])) == 0) + return 0; + return 1; +} + +static int cmp_a(m_a *a1, m_a *a2) +{ + return a1->l == a2->l && + a1->d == a2->d && + cmp_bseq(&a1->y, &a2->y); +} + +static int cmp_bseq(m_bseq *b1, m_bseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (cmp_b(&(b1->_buffer[i]), &(b2->_buffer[i])) == 0) + return 0; + return 1; +} + +static int cmp_b(m_b *b1, m_b *b2) +{ + return b1->l == b2->l && b1->c == b2->c; +} + +static int cmp_lseq(m_lseq *b1, m_lseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (b1->_buffer[i] != b2->_buffer[i]) + return 0; + return 1; +} + +static int cmp_etseq(m_etseq *b1, m_etseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (!erl_match(b1->_buffer[i], b2->_buffer[i])) + return 0; + return 1; +} + +static int cmp_et(m_et* b1, m_et *b2) +{ + return erl_match(b1->e, b2->e) && b1->l == b2->l; +} + +static int cmp_es(m_es *b1, m_es *b2) +{ + return b1->f == b2->f && b1->l == b2->l; +} + +static int cmp_arr1(m_arr1 b1, m_arr1 b2) +{ + int i; + + for (i = 0; i < 500; i++) + if (b1[i] != b2[i]) + return 0; + return 1; +} + +static int cmp_dd(m_dd b1, m_dd b2) +{ + + int i, j; + + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + if (b1[i][j] != b2[i][j]) + return 0; + return 1; +} + + + +static int cmp_strRec(m_strRec *b1, m_strRec *b2) +{ + int i, j; + + if (b1->bb != b2->bb) + return 0; + if (!cmp_str(b1->str4,b2->str4)) + return 0; + if (b1->str5._length != b2->str5._length) + return 0; + for (j = 0; j < b1->str5._length; j++) + if (b1->str5._buffer[j] != b2->str5._buffer[j]) + return 0; + if (!cmp_str(b1->str6,b2->str6)) + return 0; + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + if (b1->str7[i][j] != b2->str7[i][j]) + return 0; + for (j = 0; j < 3; j++) + if (b1->str8[j] != b2->str8[j]) + return 0; + if (!cmp_str(b1->str9,b2->str9)) + return 0; + if (b1->str10._length != b2->str10._length) + return 0; + for (j = 0; j < b1->str10._length; j++) + if (b1->str10._buffer[j] != b2->str10._buffer[j]) + return 0; + return 1; +} + + +static int cmp_sseq(m_sseq *b1, m_sseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (!cmp_str(b1->_buffer[i], b2->_buffer[i])) + return 0; + return 1; +} + + +static int cmp_pid(erlang_pid *p1, erlang_pid *p2) +{ + return cmp_str(p1->node,p2-> node) && + p1->num == p2->num && + p1->serial == p2->serial && + p1->creation == p2->creation; +} + +static int cmp_port(erlang_port *p1, erlang_port *p2) +{ + return cmp_str(p1->node,p2-> node) && p1->id == p2->id; +} + +static int cmp_ref(erlang_ref *p1, erlang_ref *p2) +{ + return cmp_str(p1->node, p2->node) && + p1->len == p2->len && + (p1->len < 1 || p1->n[0] == p2->n[0]) && + (p1->len < 2 || p1->n[1] == p2->n[1]) && + (p1->len < 3 || p1->n[2] == p2->n[2]); +} + +static int cmp_s(m_s *b1, m_s *b2) +{ + int i; + + if (b1->l != b2->l) + return 0; + if (b1->sl._length != b2->sl._length) + return 0; + for (i = 0; i < b1->sl._length; i++) + if (b1->sl._buffer[i] != b2->sl._buffer[i]) + return 0; + return 1; +} + + +static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2) +{ + int i,j; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) { + if (b1->_buffer[i]._length != b2->_buffer[i]._length) + return 0; + for (j = 0; j < b1->_buffer[i]._length; j++) + if (!cmp_str(b1->_buffer[i]._buffer[j], + b2->_buffer[i]._buffer[j])) + return 0; + } + return 1; +} + + + +static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) { + if (!cmp_sarr3(&b1->_buffer[i], &b2->_buffer[i])) + return 0; + } + return 1; +} + +static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) { + if (!cmp_arr3(b1->_buffer[i], b2->_buffer[i])) + return 0; + } + return 1; +} + +static int cmp_arr3(m_arr3 b1, m_arr3 b2) +{ + int i; + + for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++) { + if (b1[i] != b2[i]) + return 0; + } + return 1; +} + +/* Print functions */ +static void print_aseq(m_aseq *a) +{ + int i; + fprintf(stdout, "\nm_aseq size: %ld --------\n", a->_length); + for (i = 0; i < a->_length; i++) + print_a(&(a->_buffer[i])); +} + +static void print_a(m_a *a) +{ + fprintf(stdout, "\nm_a --------\n l: %ld\n d:%f\n", a->l, a->d); + print_bseq(&a->y); +} + +static void print_bseq(m_bseq *b) +{ + int i; + + fprintf(stdout, "\nm_bseq size: %ld --------\n",b->_length); + for (i = 0; i < b->_length; i++) + print_b(&(b->_buffer[i])); +} + +static void print_lseq(m_lseq *b) +{ + int i; + + fprintf(stdout, "\nm_lseq size: %ld --------\n",b->_length); + for (i = 0; i < b->_length; i++) + fprintf(stdout, "[%d]: %ld\n", i, b->_buffer[i]); +} + +static void print_b(m_b *b) +{ + fprintf(stdout, "\nm_b --------\n l: %ld\n c: %c\n", b->l, b->c); +} + + +static void print_etseq(m_etseq *b) +{ + int i; + + for (i = 0; i < b->_length; i++) { + fprintf(stdout, "[%d]:\n", i); + erl_print_term(stdout, b->_buffer[i]); + } +} + + +static void print_et(m_et* b) +{ + fprintf(stdout, "\net struct --------\n"); + erl_print_term(stdout, b->e); + fprintf(stdout, "long: %ld\n", b->l); + fprintf(stdout, "\n--------\n"); +} + +static void print_es(m_es *b) +{ + fprintf(stdout, "\nm_es --------\n f: %d\n l: %ld\n", b->f, b->l); +} + + +static void print_arr1(long a[10]) +{ + int i; + + for (i = 0; i < 10; i++) + fprintf(stdout, "\n[%d]: %ld\n", i, a[i]); +} + +static void print_dd(long a[2][3]) +{ + int i, j; + + fprintf(stdout, "\nlong dd[2][3] --------\n"); + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + fprintf(stdout, "\n[%d][%d]: %ld\n", i, j, a[i][j]); +} + + +static void print_strRec(m_strRec* sr) +{ + int i, j; + + fprintf(stdout, "\nboolean bb : %d\n",sr->bb); + fprintf(stdout, "string str4 : %s\n",sr->str4); + fprintf(stdout, "str7[2][3] :\n"); + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + fprintf(stdout, "str7[%d][%d]: %ld\n", i, j, sr->str7[i][j]); + fprintf(stdout, "str5._length : %ld\n",sr->str5._length); + for (j = 0; j < sr->str5._length; j++) + fprintf(stdout, "str5._buffer[%d]: %c\n", j, sr->str5._buffer[j]); + fprintf(stdout, "string str6 : %s\n",sr->str6); + fprintf(stdout, "str8 :\n"); + for (j = 0; j < 3; j++) + fprintf(stdout, "str8[%d]: %c\n", j, sr->str8[j]); + fprintf(stdout, "string str9 : %s\n",sr->str9); + fprintf(stdout, "str10._length : %ld\n",sr->str10._length); + for (j = 0; j < sr->str10._length; j++) + fprintf(stdout, "str10._buffer[%d]: %c\n", j, sr->str10._buffer[j]); +} + +static void print_sseq(m_sseq *b) +{ + int i; + + fprintf(stdout, "\nm_sseq size: %ld --------\n",b->_length); + for (i = 0; i < b->_length; i++) + fprintf(stdout, "%s\n", b->_buffer[i]); + +} + + +static void print_pid(erlang_pid *p) +{ + fprintf(stdout, "\nerlang_pid --------\n node: %s\n num: %d\n " + "serial: %d\n creation: %d\n", + p->node, p->num, p->serial, p->creation); +} + +static void print_port(erlang_port *p) +{ + fprintf(stdout, "\nerlang_port --------\n node: %s\n id: %d\n " + "creation: %d\n", p->node, p->id, p->creation); +} + +static void print_ref(erlang_ref *p) +{ + fprintf(stdout, "\nerlang_ref --------\n node: %s\n len: %d\n " + "n[0]: %d\n n[1]: %d\n n[2]: %d\n creation: %d\n", + p->node, p->len, p->n[0], p->n[1], p->n[2], p->creation); +} + +static void print_term(ETERM *t) +{ + fprintf(stdout, "\nETERM --------\n"); + erl_print_term(stdout, t); + fprintf(stdout, "\n--------\n"); +} + +static void print_s(m_s *p) +{ + int i; + + fprintf(stdout, "\n%ld\n", p->l); + for (i = 0; i < p->sl._length; i++) + fprintf(stdout, "\n[%d]: %ld\n", i, p->sl._buffer[i]); +} + + +static void print_ssstr3(m_ssstr3 *b1) +{ + int i,j; + + fprintf(stdout, "\nSSSTR3 --------\n"); + fprintf(stdout,"b1->_length = %ld\n",b1->_length); + for (i = 0; i < b1->_length; i++) { + fprintf(stdout,"\nb1->_buffer[%d]._length %ld\n", + i, b1->_buffer[i]._length); + for (j = 0; j < b1->_buffer[i]._length; j++) + fprintf(stdout,"b1->_buffer[%d]._buffer[%d] = %s\n", + i, j, b1->_buffer[i]._buffer[j]); + } + fprintf(stdout, "\n--------\n"); +} + +static void print_wstr(CORBA_wchar *ws) +{ + int i = 0; + + fprintf(stdout, "\nwstr --------\n"); + while (ws[i]) { + fprintf(stdout, "[%d]: %ld\n", i, ws[i]); + i++; + } + fprintf(stdout, "\n--------\n"); +} + + +static void print_ssarr3(m_ssarr3 *b1) +{ + int i; + + fprintf(stdout, "\nssarr3 --------\n"); + fprintf(stdout,"length: %ld\n",b1->_length); + fprintf(stdout, "buffer:\n"); + for (i = 0; i < b1->_length; i++) + print_sarr3(&b1->_buffer[i]); + fprintf(stdout, "\n--------\n"); +} + +static void print_sarr3(m_sarr3 *b1) +{ + int i; + + fprintf(stdout, "\nsarr3 --------\n"); + fprintf(stdout,"length: %ld\n",b1->_length); + fprintf(stdout, "buffer:\n"); + for (i = 0; i < b1->_length; i++) + print_arr3(b1->_buffer[i]); + fprintf(stdout, "\n--------\n"); +} + +static void print_arr3(m_arr3 b1) +{ + int i; + + fprintf(stdout, "\narr3 --------\n"); + for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++) + fprintf(stdout, "%ld ", b1[i]); + fprintf(stdout, "\n--------\n"); +} + +static void free_etseq_buf(m_etseq *b) +{ + int i; + + for (i = 0; i < b->_length; i++) + erl_free_term(b->_buffer[i]); +} + +static void free_et(m_et* b) +{ + erl_free_term(b->e); +} + +static void showtime(MyTimeval *start, MyTimeval *stop) +{ + MyTimeval elapsed; + + elapsed.tv_sec = stop->tv_sec - start->tv_sec; + elapsed.tv_usec = stop->tv_usec - start->tv_usec; + while (elapsed.tv_usec < 0) { + elapsed.tv_sec -= 1; + elapsed.tv_usec += 1000000; + } + fprintf(stderr,"%ld.%06ld seconds\n",elapsed.tv_sec, elapsed.tv_usec); +} + +static void my_gettimeofday(MyTimeval *tv) +#ifdef __WIN32__ +#define EPOCH_JULIAN_DIFF 11644473600i64 +{ + SYSTEMTIME t; + FILETIME ft; + LONGLONG lft; + + GetSystemTime(&t); + SystemTimeToFileTime(&t, &ft); + memcpy(&lft, &ft, sizeof(lft)); + tv->tv_usec = (long) ((lft / 10i64) % 1000000i64); + tv->tv_sec = (long) ((lft / 10000000i64) - EPOCH_JULIAN_DIFF); +} +#elif defined VXWORKS +{ + int rate = sysClkRateGet(); /* Ticks per second */ + unsigned long ctick = tickGet(); + tv->tv_sec = ctick / rate; /* secs since reboot */ + tv->tv_usec = ((ctick - (tv->tv_sec * rate))*1000000)/rate; +} +#else +{ + gettimeofday(tv, NULL); +} +#endif diff --git a/lib/ic/test/c_client_erl_server_SUITE_data/c_erl_test.idl b/lib/ic/test/c_client_erl_server_SUITE_data/c_erl_test.idl new file mode 100644 index 0000000000..ccb8f54508 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_SUITE_data/c_erl_test.idl @@ -0,0 +1,174 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 2001-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +#include "erlang.idl" + + +const short TestConst = 1; + +module m { + + const short TestConst = 2; + + struct b { + long l; + char c; + }; + + struct simple { + long l; + b b_t; + }; + + enum fruit {orange, banana, apple, peach, pear}; + + typedef sequence<long> lseq; + + typedef sequence<b> bseq; + + struct a { + long l; + bseq y; + double d; + }; + + typedef sequence<a> aseq; + + typedef sequence<string> sseq; + typedef string str; + typedef long myLong; + + typedef long arr1[500], dd[2][3]; + + typedef erlang::term apa; + typedef erlang::port banan; + + typedef sequence<erlang::term> etseq; + + struct s { + long l; + sequence<long> sl; + }; + + struct es { + fruit f; + myLong l; + }; + + struct et { + erlang::term e; + long l; + }; + + + typedef sequence<char> str1; + typedef string<12> str2; + typedef char str3[3]; + + typedef sequence<string> sstr3; // sequence of string + typedef sequence<sstr3> ssstr3; // sequence of sequences of strings + + typedef long arr3[3]; // array of long + typedef sequence<arr3> sarr3; // sequence of array + typedef sequence<sarr3> ssarr3; // sequence of sequnces of arrays of strings + + struct strRec{ + boolean bb; + string str4; + long str7[3][2]; + sequence<char> str5; + string<12> str6; + str3 str8; + str2 str9; + str1 str10; + }; + + + struct dyn { + long l; + sequence<long> sl; + }; + typedef dyn arr2[1][2]; + + + interface i { + + const short TestConst = 3; + + //arr2 suck(in arr2 x, out arr2 y ); + + ///////////////////////////////// attribute long l; + + // simple types + void void_test(); + long long_test(in long a, out long a1); + long long longlong_test(in long long a, out long long a1); + unsigned short ushort_test(in unsigned short a, out unsigned short a1); + unsigned long ulong_test(in unsigned long a, out unsigned long a1); + unsigned long long ulonglong_test(in unsigned long long a, out unsigned long long a1); + double double_test(in double a, out double a1); + char char_test(in char a, out char a1); + wchar wchar_test(in wchar a, out wchar a1); + octet octet_test(in octet a, out octet a1); + boolean bool_test(in boolean a, out boolean a1); + + // Seq. and struct tests + b struct_test(in b a, out b a1); + es struct2_test(in es a, out es a1); + //simple struct3_test(in simple x, out simple y); + bseq seq1_test(in bseq a, out bseq a1); + aseq seq2_test(in aseq a, out aseq a1); + lseq seq3_test(in lseq a, out lseq a1); + ssstr3 seq4_test(in ssstr3 a, out ssstr3 a1); + ssarr3 seq5_test(in ssarr3 a, out ssarr3 a1); + + // Array tests + arr1 array1_test(in arr1 a, out arr1 a1); + dd array2_test(in dd a, out dd a1); + + // enum test + fruit enum_test(in fruit a, out fruit a1); + + // string tests + string string1_test(in string a, out string a1); + wstring wstring1_test(in wstring a, out wstring a1); + sseq string2_test(in sseq a, out sseq a1); + str string3_test(in str a, out str a1); + strRec string4_test(in strRec a, out strRec a1); + + // Special erlang types + erlang::pid pid_test(in erlang::pid a, out erlang::pid a1); + erlang::port port_test(in erlang::port a, out erlang::port a1); + erlang::ref ref_test(in erlang::ref a, out erlang::ref a1); + erlang::term term_test(in erlang::term a, out erlang::term a1); + + // typedef test + long typedef_test(in apa a, in banan b, out apa a1, out banan b1); + + // inlined seq. test + s inline_sequence_test(in s a, out s a1); + + // term seq. test + etseq term_sequence_test(in etseq a, out etseq a1); + // term struct test + et term_struct_test(in et a, out et a1); + + }; + +}; diff --git a/lib/ic/test/c_client_erl_server_SUITE_data/erl_server.erl b/lib/ic/test/c_client_erl_server_SUITE_data/erl_server.erl new file mode 100644 index 0000000000..dffbbb059c --- /dev/null +++ b/lib/ic/test/c_client_erl_server_SUITE_data/erl_server.erl @@ -0,0 +1,28 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(erl_server). + +-export([run/0, stop/0]). + +run() -> + m_i:oe_create(). + +stop() -> + gen_server:cast(cidl_test, stop). diff --git a/lib/ic/test/c_client_erl_server_SUITE_data/m_i_impl.erl b/lib/ic/test/c_client_erl_server_SUITE_data/m_i_impl.erl new file mode 100644 index 0000000000..cfcaa793a5 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_SUITE_data/m_i_impl.erl @@ -0,0 +1,161 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(m_i_impl). +-include("m.hrl"). + +-export([init/1, terminate/2, void_test/1, long_test/2, ushort_test/2, + longlong_test/2, ulong_test/2, ulonglong_test/2, + double_test/2, char_test/2, wchar_test/2, octet_test/2, + bool_test/2, struct_test/2, struct2_test/2, seq1_test/2, + seq2_test/2, seq3_test/2, seq4_test/2, seq5_test/2, + array1_test/2, array2_test/2, enum_test/2, string1_test/2, + string2_test/2, string3_test/2, string4_test/2, pid_test/2, + port_test/2, ref_test/2, term_test/2, typedef_test/3, + inline_sequence_test/2, '_set_l'/2, '_get_l'/1, + term_struct_test/2, term_sequence_test/2, wstring1_test/2]). + +-define(PRINTDEBUG(Case), + io:format("erl_server: case: ~p~n" + "erl_server: location: ~p~n", [Case, [?FILE, ?LINE]])). +-define(PRINTDEBUG2(Case, Msg), + io:format("erl_server: case: ~p~n" + "erl_server: Msg: ~p~n" + "erl_server: location: ~p~n", [Case, Msg, [?FILE, ?LINE]])). + +init(Env) -> + {ok, []}. + +terminate(F, R) -> + ok. + +'_get_l'(State) -> + ?PRINTDEBUG("_get_l"), + {reply, State, State}. +void_test(State) -> + ?PRINTDEBUG("void_test"), + {reply, ok, State}. + +'_set_l'(State, V) -> + ?PRINTDEBUG2("_set_l", V), + {reply, ok, V}. +ushort_test(State, V) -> + ?PRINTDEBUG2("ushort_test", V), + {reply, {V, V}, State}. +long_test(State, V) -> + ?PRINTDEBUG2("long_test", V), + {reply, {V, V}, State}. +longlong_test(State, V) -> + ?PRINTDEBUG2("longlong_test", V), + {reply, {V, V}, State}. +ulong_test(State, V) -> + ?PRINTDEBUG2("ulong_test", V), + {reply, {V, V}, State}. +ulonglong_test(State, V) -> + ?PRINTDEBUG2("ulonglong_test", V), + {reply, {V, V}, State}. +double_test(State, V) -> + ?PRINTDEBUG2("double_test", V), + {reply, {V, V}, State}. +char_test(State, V) -> + ?PRINTDEBUG2("char_test", V), + {reply, {V, V}, State}. +wchar_test(State, V) -> + ?PRINTDEBUG2("wchar_test", V), + {reply, {V, V}, State}. +octet_test(State, V) -> + ?PRINTDEBUG2("octet_test", V), + {reply, {V, V}, State}. +bool_test(State, V) -> + ?PRINTDEBUG2("bool_test", V), + {reply, {V, V}, State}. + +struct_test(State, V) -> + ?PRINTDEBUG2("struct_test", V), + {reply, {V, V}, State}. +struct2_test(State, V) -> + ?PRINTDEBUG2("struct2_test", V), + {reply, {V, V}, State}. +seq1_test(State, V) -> + ?PRINTDEBUG2("seq1_test", V), + {reply, {V, V}, State}. +seq2_test(State, V) -> + ?PRINTDEBUG2("seq2_test", V), + {reply, {V, V}, State}. +seq3_test(State, V) -> + ?PRINTDEBUG2("seq3_test", V), + {reply, {V, V}, State}. +seq4_test(State, V) -> + ?PRINTDEBUG2("seq4_test", V), + {reply, {V, V}, State}. +seq5_test(State, V) -> + ?PRINTDEBUG2("seq5_test", V), + {reply, {V, V}, State}. +array1_test(State, V) -> + ?PRINTDEBUG2("array1_test", V), + {reply, {V, V}, State}. +array2_test(State, V) -> + ?PRINTDEBUG2("array2_test", V), + {reply, {V, V}, State}. +enum_test(State, V) -> + ?PRINTDEBUG2("enum_test", V), + {reply, {V, V}, State}. +string1_test(State, V) -> + ?PRINTDEBUG2("string1_test", V), + {reply, {V, V}, State}. +string2_test(State, V) -> + ?PRINTDEBUG2("string2_test", V), + {reply, {V, V}, State}. +string3_test(State, V) -> + ?PRINTDEBUG2("string3_test", V), + {reply, {V, V}, State}. +string4_test(State, V) -> + ?PRINTDEBUG2("string4_test", V), + {reply, {V, V}, State}. +pid_test(State, V) -> + ?PRINTDEBUG2("pid_test", V), + {reply, {V, V}, State}. +port_test(State, V) -> + ?PRINTDEBUG2("port_test", binary_to_list(term_to_binary(V))), + {reply, {V, V}, State}. +ref_test(State, V) -> + ?PRINTDEBUG2("ref_test", binary_to_list(term_to_binary(V))), + {reply, {V, V}, State}. +term_test(State, V) -> + ?PRINTDEBUG2("term_test", V), + {reply, {V, V}, State}. +typedef_test(State, A, B) -> + ?PRINTDEBUG2("typedef_test", [A,B]), + {reply, {4711, A, B}, State}. +inline_sequence_test(State, V) -> + ?PRINTDEBUG2("inline_sequence_test", V), + {reply, {V, V}, State}. +term_sequence_test(State, V) -> + ?PRINTDEBUG2("term_sequence_test", V), + {reply, {V, V}, State}. +term_struct_test(State, V) -> + ?PRINTDEBUG2("term_struct_test", V), + {reply, {V, V}, State}. +wstring1_test(State, V) -> + ?PRINTDEBUG2("wstring1_test", V), + {reply, {V, V}, State}. + + + + diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE.erl b/lib/ic/test/c_client_erl_server_proto_SUITE.erl new file mode 100644 index 0000000000..58309a2221 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_SUITE.erl @@ -0,0 +1,315 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +%%---------------------------------------------------------------------- +%% Purpose : Test suite for c-client/erl-server +%%---------------------------------------------------------------------- + +-module(c_client_erl_server_proto_SUITE). +-include("test_server.hrl"). + +-export([init_per_testcase/2, fin_per_testcase/2, + all/1, void_test/1, long_test/1, long_long_test/1, + unsigned_short_test/1, unsigned_long_test/1, + unsigned_long_long_test/1, double_test/1, char_test/1, + wchar_test/1, octet_test/1, bool_test/1, struct_test/1, + struct2_test/1, seq1_test/1, seq2_test/1, seq3_test/1, + seq4_test/1, seq5_test/1, array1_test/1, array2_test/1, + enum_test/1, string1_test/1, string2_test/1, string3_test/1, + string4_test/1, pid_test/1, port_test/1, ref_test/1, term_test/1, + typedef_test/1, inline_sequence_test/1, term_sequence_test/1, + term_struct_test/1, wstring1_test/1]). + +-define(DEFAULT_TIMEOUT, 20000). +-define(PORT_TIMEOUT, 15000). +-define(ERLANG_SERVER_NAME, idl_erlang_server). +-define(C_CLIENT_NODE_NAME, c_client_idl_test). + +%% Add/remove code path and watchdog before/after each test case. +%% +init_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:add_patha(DataDir), + + %% Since other test suites use the module m_i, we have + %% to make sure we are using the right m_i module. + code:purge(m_i), + code:load_file(m_i), + + WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:del_path(DataDir), + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of IC with a C-client and an Erlang generic server. " + "The communication is via Erlang distribution."; +all(suite) -> + [void_test, long_test, long_long_test, unsigned_short_test, + unsigned_long_test, unsigned_long_long_test, double_test, + char_test, wchar_test, octet_test, bool_test, struct_test, + struct2_test, seq1_test, seq2_test, seq3_test, seq4_test, + seq5_test, array1_test, array2_test, enum_test, string1_test, + string2_test, string3_test, string4_test, pid_test, port_test, + ref_test, term_test, typedef_test, inline_sequence_test, + term_sequence_test, term_struct_test, wstring1_test]. + + +array1_test(doc) -> ""; +array1_test(suite) -> []; +array1_test(Config) -> + do_test(array1_test, Config). + +array2_test(doc) -> ""; +array2_test(suite) -> []; +array2_test(Config) -> + do_test(array2_test, Config). + +bool_test(doc) -> ""; +bool_test(suite) -> []; +bool_test(Config) -> + do_test(bool_test, Config). + +char_test(doc) -> ""; +char_test(suite) -> []; +char_test(Config) -> + do_test(char_test, Config). + +double_test(doc) -> ""; +double_test(suite) -> []; +double_test(Config) -> + do_test(double_test, Config). + +enum_test(doc) -> ""; +enum_test(suite) -> []; +enum_test(Config) -> + do_test(enum_test, Config). + +inline_sequence_test(doc) -> ""; +inline_sequence_test(suite) -> []; +inline_sequence_test(Config) -> + do_test(inline_sequence_test, Config). + +long_long_test(doc) -> ""; +long_long_test(suite) -> []; +long_long_test(Config) -> + do_test(long_long_test, Config). + +long_test(doc) -> ""; +long_test(suite) -> []; +long_test(Config) -> + do_test(long_test, Config). + +octet_test(doc) -> ""; +octet_test(suite) -> []; +octet_test(Config) -> + do_test(octet_test, Config). + +pid_test(doc) -> ""; +pid_test(suite) -> []; +pid_test(Config) -> + do_test(pid_test, Config). + +port_test(doc) -> ""; +port_test(suite) -> []; +port_test(Config) -> + do_test(port_test, Config). + +ref_test(doc) -> ""; +ref_test(suite) -> []; +ref_test(Config) -> + do_test(ref_test, Config). + +seq1_test(doc) -> ""; +seq1_test(suite) -> []; +seq1_test(Config) -> + do_test(seq1_test, Config). + +seq2_test(doc) -> ""; +seq2_test(suite) -> []; +seq2_test(Config) -> + do_test(seq2_test, Config). + +seq3_test(doc) -> ""; +seq3_test(suite) -> []; +seq3_test(Config) -> + do_test(seq3_test, Config). + +seq4_test(doc) -> ""; +seq4_test(suite) -> []; +seq4_test(Config) -> + do_test(seq4_test, Config). + +seq5_test(doc) -> ""; +seq5_test(suite) -> []; +seq5_test(Config) -> + do_test(seq5_test, Config). + +string1_test(doc) -> ""; +string1_test(suite) -> []; +string1_test(Config) -> + do_test(string1_test, Config). + +string2_test(doc) -> ""; +string2_test(suite) -> []; +string2_test(Config) -> + do_test(string2_test, Config). + +string3_test(doc) -> ""; +string3_test(suite) -> []; +string3_test(Config) -> + do_test(string3_test, Config). + +string4_test(doc) -> ""; +string4_test(suite) -> []; +string4_test(Config) -> + do_test(string4_test, Config). + +struct2_test(doc) -> ""; +struct2_test(suite) -> []; +struct2_test(Config) -> + do_test(struct2_test, Config). + +struct_test(doc) -> ""; +struct_test(suite) -> []; +struct_test(Config) -> + do_test(struct_test, Config). + +term_sequence_test(doc) -> ""; +term_sequence_test(suite) -> []; +term_sequence_test(Config) -> + do_test(term_sequence_test, Config). + +term_struct_test(doc) -> ""; +term_struct_test(suite) -> []; +term_struct_test(Config) -> + do_test(term_struct_test, Config). + +term_test(doc) -> ""; +term_test(suite) -> []; +term_test(Config) -> + do_test(term_test, Config). + +typedef_test(doc) -> ""; +typedef_test(suite) -> []; +typedef_test(Config) -> + do_test(typedef_test, Config). + +unsigned_long_long_test(doc) -> ""; +unsigned_long_long_test(suite) -> []; +unsigned_long_long_test(Config) -> + do_test(unsigned_long_long_test, Config). + +unsigned_long_test(doc) -> ""; +unsigned_long_test(suite) -> []; +unsigned_long_test(Config) -> + do_test(unsigned_long_test, Config). + +unsigned_short_test(doc) -> ""; +unsigned_short_test(suite) -> []; +unsigned_short_test(Config) -> + do_test(unsigned_short_test, Config). + +void_test(doc) -> ""; +void_test(suite) -> []; +void_test(Config) -> + do_test(void_test, Config). + +wchar_test(doc) -> ""; +wchar_test(suite) -> []; +wchar_test(Config) -> + do_test(wchar_test, Config). + +wstring1_test(doc) -> ""; +wstring1_test(suite) -> []; +wstring1_test(Config) -> + do_test(wstring1_test, Config). + + +%% It is here that all tests really are done. +%% + +do_test(Case, Config) -> + %% Trap exits + process_flag(trap_exit, true), + %% Start the server + {ok, _Pid} = m_i:oe_create_link([], {local, ?ERLANG_SERVER_NAME}), + Node = atom_to_list(node()), + %% [NodeName, HostName] = string:tokens(Node, "@"), + DataDir = ?config(data_dir, Config), + %% io:format("~p: data directory: ~p~n", [?MODULE, DataDir]), + Cookie = atom_to_list(erlang:get_cookie()), + %% Start C-client node as a port program. + Cmd = filename:join([DataDir, "c_client"]) ++ + " -this-node-name " ++ atom_to_list(?C_CLIENT_NODE_NAME) ++ + " -peer-node " ++ Node ++ + " -peer-process-name " ++ atom_to_list(?ERLANG_SERVER_NAME) ++ + " -cookie " ++ Cookie ++ + " -test-case " ++ atom_to_list(Case), + Port = open_port({spawn, Cmd}, [exit_status, eof, stderr_to_stdout]), + Res = wait_for_completion(Port), + %% Kill off node if there was timeout + case Res of + {error, timeout} -> + catch rpc:cast(?C_CLIENT_NODE_NAME, erlang, halt, [1]); + _ -> + ok + end, + process_flag(trap_exit, false), + catch m_i:stop(?ERLANG_SERVER_NAME), + ok = Res. + + +%% Wait for eof *and* exit status, but return if exit status indicates +%% an error, or we have been waiting more than PORT_TIMEOUT seconds. +%% +wait_for_completion(Port) -> + wait_for_completion(Port, 0). + +wait_for_completion(Port, N) when N < 2 -> + receive + {Port, {data, Bytes}} -> + %% Relay output + io:format("~s", [Bytes]), + wait_for_completion(Port, N); + {Port, {exit_status, 0}} -> + wait_for_completion(Port, N + 1); + {Port, {exit_status, Status}} -> + {error, Status}; + {Port, eof} -> + wait_for_completion(Port, N + 1); + {'EXIT', Port, Reason} -> + io:format("Port exited with reason: ~w~n", [Reason]), + wait_for_completion(Port, N); + {'EXIT', From, Reason} -> + io:format("Got unexpected exit: ~p~n", [{'EXIT', From, Reason}]), + wait_for_completion(Port, N) + after ?PORT_TIMEOUT -> + {error, timeout} + end; +wait_for_completion(_, _) -> + ok. + + + diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/Makefile.src b/lib/ic/test/c_client_erl_server_proto_SUITE_data/Makefile.src new file mode 100644 index 0000000000..3dcd1d9387 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_SUITE_data/Makefile.src @@ -0,0 +1,146 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# Makefile.src for c_client_erl_server test +# Note: This file *must* work for both Unix and Windows +# +# We use both `rm' (Unix) and `del' (Windows) for removing files, but +# with a `-' in front so that the error in not finding `rm' (`del') on +# Windows (Unix) is ignored. +# +# VxWorks? XXX +# + +.SUFFIXES: +.SUFFIXES: .c .h .erl .idl @obj@ .@EMULATOR@ + + +# Variables from ts: +# + +ERL_INCLUDE = @erl_include@ + +IC_INCLUDE_PATH = @ic_include_path@ +IC_LIB = @ic_libpath@@DS@@ic_lib@ + +ERL_INTERFACE_INCLUDE = @erl_interface_include@ +ERL_INTERFACE_LIB = @erl_interface_libpath@@DS@@erl_interface_lib@ +ERL_INTERFACE_EILIB = @erl_interface_libpath@@DS@@erl_interface_eilib@ +ERL_INTERFACE_THREADLIB = @erl_interface_threadlib@ +ERL_INTERFACE_SOCK_LIBS = @erl_interface_sock_libs@ + +CC = @CC@ +## XXX Should set warning flag with a DEBUG_FLAG +CFLAGS = @CFLAGS@ @DEFS@ -I@erl_include@ \ + -I@ic_include_path@ -I@erl_interface_include@ + +LD = @LD@ +LDFLAGS = @CROSSLDFLAGS@ +LIBS = $(IC_LIB) $(ERL_INTERFACE_LIB) $(ERL_INTERFACE_EILIB) \ + $(ERL_INTERFACE_THREADLIB) @LIBS@ $(ERL_INTERFACE_SOCK_LIBS) +ERLC = erlc + +# Generated C header files +GEN_H_FILES = \ + m.h \ + m_i.h \ + oe_c_erl_test.h + +# Generated C files +GEN_C_FILES = \ + m.c \ + m_i.c \ + oe_c_erl_test.c \ + oe_code_m_a.c \ + oe_code_m_arr1.c \ + oe_code_m_arr2.c \ + oe_code_m_arr3.c \ + oe_code_m_aseq.c \ + oe_code_m_b.c \ + oe_code_m_bseq.c \ + oe_code_m_dd.c \ + oe_code_m_dyn.c \ + oe_code_m_dyn_sl.c \ + oe_code_m_es.c \ + oe_code_m_et.c \ + oe_code_m_etseq.c \ + oe_code_m_fruit.c \ + oe_code_m_lseq.c \ + oe_code_m_s.c \ + oe_code_m_s_sl.c \ + oe_code_m_sarr3.c \ + oe_code_m_simple.c \ + oe_code_m_ssarr3.c \ + oe_code_m_sseq.c \ + oe_code_m_ssstr3.c \ + oe_code_m_sstr3.c \ + oe_code_m_str1.c \ + oe_code_m_str3.c \ + oe_code_m_strRec.c \ + oe_code_m_strRec_str5.c \ + oe_code_m_strRec_str7.c + +GEN_HRL_FILES = \ + m.hrl \ + m_i.hrl \ + oe_c_erl_test.hrl + +GEN_ERL_FILES = \ + m.erl \ + m_arr2.erl \ + m_arr3.erl \ + m_i.erl \ + m_str3.erl \ + oe_c_erl_test.erl + +C_FILES = $(GEN_C_FILES) c_client.c my.c + +OBJS = $(C_FILES:.c=@obj@) + +PGMS = c_client@exe@ + +ERL_FILES = $(GEN_ERL_FILES) m_i_impl.erl + +EBINS = $(ERL_FILES:.erl=.@EMULATOR@) + + +all: $(PGMS) $(EBINS) + +clean: + -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + +$(PGMS): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_client}" \ + "+{user_protocol,my}" c_erl_test.idl + +$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" c_erl_test.idl + +.c@obj@: + $(CC) -c -o $*@obj@ $(CFLAGS) $< + +.erl.@EMULATOR@: + $(ERLC) -I $(IC_INCLUDE_PATH) $< + diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_client.c b/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_client.c new file mode 100644 index 0000000000..f352b91fd5 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_client.c @@ -0,0 +1,1763 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2003-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/* C-client for test of IC. + * + * TODO: + * + * 1. XXX #includes for VxWorks, Windows + */ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef __WIN32__ +# include <unistd.h> +#endif + +#include <string.h> + +#ifdef __WIN32__ +# include <time.h> +# include <sys/timeb.h> +#elif defined VXWORKS +#include <time.h> +#include <sys/times.h> +#else +#include <sys/time.h> +#endif + +#include <ctype.h> + +#ifdef __WIN32__ +# include <winsock2.h> +# include <windows.h> +#else +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# include <netdb.h> +#endif + +#include "ei.h" +#include "erl_interface.h" +#include "m_i.h" + +#define HOSTNAMESZ 256 +#define NODENAMESZ 512 + +#define INBUFSZ 10 +#define OUTBUFSZ 0 + +#define MAXTRIES 5 + +#define CHECK_EXCEPTION(x) \ + if ((x)->_major != CORBA_NO_EXCEPTION) { \ + fprintf(stderr,"\n\nException: %s\n\n", \ + (char *)CORBA_exception_value((x))); \ + CORBA_exception_free((x)); \ + return -1; \ + } \ + +/* XXX Should free things here too! */ +#define RETURN_IF_OK(x) \ + if ((x)) {\ + fprintf(stdout, "ok\n");\ + return 0;\ + }\ + +#define cmp_str(x,y) (!strcmp((x),(y))) +#define cmp_wstr(x,y) (!ic_wstrcmp((x),(y))) + +typedef CORBA_Environment IC_Env; + +typedef int (*TestFunc)(IC_Env *); +typedef struct { + char *name; + TestFunc func; +} TestCase; + +static char longtext[] = +"Introduction The IC application is an IDL compiler implemented in Erlang." +" The IDL compiler generates client stubs and server skeletons." +" Several back-ends are supported, and they fall into three main groups." +" For more details on IC compiler options consult the ic(3) manual page." +" Argument passing cases 1 Caller allocates all necessary storage," +" except that which may be encapsulated and managed within the parameter itself." +" 2 The caller allocates a pointer and passes it by reference to the callee." +" The callee sets the pointer to point to a valid instance of the parameter's type." +" The caller is responsible for releasing the returned storage." +" Following completion of a request, the caller is not allowed to modify any values" +" in the returned storage. To do so the caller must first copy the returned instance" +" into a new instance, then modify the new instance. 3 The caller allocates a" +" pointer to an array slice which has all the same dimensions of the original" +" array except the first, and passes it by reference to the callee. The callee sets" +" the pointer to point to a valid instance of the array. The caller is responsible for" +" releasing the returned storage. Following completion of a request, the caller is not" +" allowed to modify any values in the returned storage. To do so the caller must first" +" copy the returned instance into a new instance, then modify the new instance." +" Generated Files Two files will be generated for each scope. One set of files will be" +" generated for each module and each interface scope. An extra set is generated for" +" those definitions at top level scope. One of the files is a header file(.h), and the" +" other file is a C source code file (.c). In addition to these files a number of C" +" source files will be generated for type encodings, they are named according to the " +"following template: oe_code_<type>.c."; +static char this_node[NODENAMESZ + 1]; +static char *progname; + +/* Test function prototypes */ + +static int void_test(IC_Env *env); +static int long_test(IC_Env *env); +static int long_long_test(IC_Env *env); +static int unsigned_short_test(IC_Env *env); +static int unsigned_long_test(IC_Env *env); +static int unsigned_long_long_test(IC_Env *env); +static int double_test(IC_Env *env); +static int char_test(IC_Env *env); +static int wchar_test(IC_Env *env); +static int octet_test(IC_Env *env); +static int bool_test(IC_Env *env); +static int struct_test(IC_Env *env); +static int struct2_test(IC_Env *env); +static int seq1_test(IC_Env *env); +static int seq2_test(IC_Env *env); +static int seq3_test(IC_Env *env); +static int seq4_test(IC_Env *env); +static int seq5_test(IC_Env *env); +static int array1_test(IC_Env *env); +static int array2_test(IC_Env *env); +static int enum_test(IC_Env *env); +static int string1_test(IC_Env *env); +static int string2_test(IC_Env *env); +static int string3_test(IC_Env *env); +static int string4_test(IC_Env *env); +static int pid_test(IC_Env *env); +static int port_test(IC_Env *env); +static int ref_test(IC_Env *env); +static int term_test(IC_Env *env); +static int typedef_test(IC_Env *env); +static int inline_sequence_test(IC_Env *env); +static int term_sequence_test(IC_Env *env); +static int term_struct_test(IC_Env *env); +static int wstring1_test(IC_Env *env); + +static TestCase test_cases[] = { + {"void_test", void_test}, + {"long_test", long_test}, + {"long_long_test", long_long_test}, + {"unsigned_short_test", unsigned_short_test}, + {"unsigned_long_test", unsigned_long_test}, + {"unsigned_long_long_test", unsigned_long_long_test}, + {"double_test", double_test}, + {"char_test", char_test}, + {"wchar_test", wchar_test}, + {"octet_test", octet_test}, + {"bool_test", bool_test}, + {"struct_test", struct_test}, + {"struct2_test", struct2_test}, + {"seq1_test", seq1_test}, + {"seq2_test", seq2_test}, + {"seq3_test", seq3_test}, + {"seq4_test", seq4_test}, + {"seq5_test", seq5_test}, + {"array1_test", array1_test}, + {"array2_test", array2_test}, + {"enum_test", enum_test}, + {"string1_test", string1_test}, + {"string2_test", string2_test}, + {"string3_test", string3_test}, + {"string4_test", string4_test}, + {"pid_test", pid_test}, + {"port_test", port_test}, + {"ref_test", ref_test}, + {"term_test", term_test}, + {"typedef_test", typedef_test}, + {"inline_sequence_test", inline_sequence_test}, + {"term_sequence_test", term_sequence_test}, + {"term_struct_test", term_struct_test}, + {"wstring1_test", wstring1_test}, + {"", NULL} +}; + +/* Other prototypes */ +static int cmp_aseq(m_aseq *a1, m_aseq *a2); +static int cmp_a(m_a *a1, m_a *a2); +static int cmp_bseq(m_bseq *b1, m_bseq *b2); +static int cmp_b(m_b *b1, m_b *b2); +static int cmp_lseq(m_lseq *b1, m_lseq *b2); +static int cmp_etseq(m_etseq *b1, m_etseq *b2); +static int cmp_et(m_et* b1, m_et *b2); +static int cmp_es(m_es *b1, m_es *b2); +static int cmp_arr1(m_arr1 b1, m_arr1 b2); +static int cmp_dd(m_dd b1, m_dd b2); +static int cmp_strRec(m_strRec *b1, m_strRec *b2); +static int cmp_sseq(m_sseq *b1, m_sseq *b2); +static int cmp_pid(erlang_pid *p1, erlang_pid *p2); +static int cmp_port(erlang_port *p1, erlang_port *p2); +static int cmp_ref(erlang_ref *p1, erlang_ref *p2); +static int cmp_s(m_s *b1, m_s *b2); +static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2); +static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2); +static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2); +static int cmp_arr3(m_arr3 b1, m_arr3 b2); + +static void print_aseq(m_aseq *a); +static void print_a(m_a *a); +static void print_bseq(m_bseq *b); +static void print_lseq(m_lseq *b); +static void print_b(m_b *b); +static void print_etseq(m_etseq *b); +static void print_et(m_et* b); +static void print_es(m_es *b); +static void print_arr1(long a[500]); +static void print_dd(long a[2][3]); +static void print_strRec(m_strRec* sr); +static void print_sseq(m_sseq *b); +static void print_pid(erlang_pid *p); +static void print_port(erlang_port *p); +static void print_ref(erlang_ref *p); +static void print_term(ETERM *t); +static void print_s(m_s *p); +static void print_ssstr3(m_ssstr3 *b1); +static void print_ssarr3(m_ssarr3 *b1); +static void print_sarr3(m_sarr3 *b1); +static void print_arr3(m_arr3 b1); +static void print_wstr(CORBA_wchar *ws); + +static void free_etseq_buf(m_etseq *b); +static void free_et(m_et* b); + +#ifdef __WIN32__ +typedef struct { + long tv_sec; + long tv_usec; +} MyTimeval; +#else +typedef struct timeval MyTimeval; +#endif +static void my_gettimeofday(MyTimeval *tv); +static void showtime(MyTimeval *start, MyTimeval *stop); +static void usage(void); +static void done(int r); + + + +/* main */ + +#ifdef VXWORKS +int client(int argc, char **argv) +#else +int main(int argc, char **argv) +#endif +{ + struct hostent *hp; + erlang_pid pid; + MyTimeval start, stop; + int i, fd, ires, tres; + IC_Env *env; + int tries = 0; + char *this_node_name = NULL; + char *peer_node = NULL; + char *peer_process_name = NULL; + char *cookie = NULL; + char host[HOSTNAMESZ + 1]; + TestFunc test_func = NULL; + TestCase *test_case; + char *test_case_name = NULL; + +#ifdef __WIN32__ + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD(2, 0); + + if (WSAStartup(wVersionRequested, &wsaData) != 0) { + fprintf(stderr, "Could not load winsock2 v2.0 compatible DLL"); + exit(1); + } +#endif + + progname = argv[0]; + host[HOSTNAMESZ] = '\0'; + if (gethostname(host, HOSTNAMESZ) < 0) { + fprintf(stderr, "Can't find own hostname\n"); + done(1); + } + if ((hp = gethostbyname(host)) == 0) { + fprintf(stderr, "Can't get ip address for host %s\n", host); + done(1); + } + for (i = 1; i < argc; i++) { + if (cmp_str(argv[i], "-help")) { + usage(); + done(0); + } else if (cmp_str(argv[i], "-this-node-name")) { + i++; + this_node_name = argv[i]; + } else if (cmp_str(argv[i], "-peer-node")) { + i++; + peer_node = argv[i]; + } else if (cmp_str(argv[i], "-peer-process-name")) { + i++; + peer_process_name = argv[i]; + } else if (cmp_str(argv[i], "-cookie")) { + i++; + cookie = argv[i]; + } else if (cmp_str(argv[i], "-test-case")) { + i++; + test_case_name = argv[i]; + } else { + fprintf(stderr, "Error : invalid argument \"%s\"\n", argv[i]); + usage(); + done(1); + } + } + + if (this_node_name == NULL || peer_node == NULL || test_case_name == NULL + || peer_process_name == NULL || cookie == NULL) { + fprintf(stderr, "Error: missing option\n"); + usage(); + done(1); + } + + test_case = test_cases; + while (test_case->func) { + if (cmp_str(test_case->name, test_case_name)) { + test_func = test_case->func; + break; + } + test_case++; + } + if (test_func == NULL) { + fprintf(stderr, "Error: illegal test case: \"%s\"\n", test_case_name); + done(1); + } + + /* Behead hostname at first dot */ + for (i=0; host[i] != '\0'; i++) { + if (host[i] == '.') { host[i] = '\0'; break; } + } + sprintf(this_node, "%s@%s", this_node_name, host); + fprintf(stderr, "c_client: this node: \"%s\"\n", this_node); + fprintf(stderr, "c_client: peer node: \"%s\"\n", peer_node); + fprintf(stderr, "c_client: test case: \"%s\"\n", test_case_name); + + fprintf(stderr, "c_client: starting\n"); + + /* initialize erl_interface */ + erl_init(NULL, 0); + + for (tries = 0; tries < MAXTRIES; tries++) { + + /* connect to erlang node */ + + ires = erl_connect_xinit(host, this_node_name, this_node, + (struct in_addr *)*hp->h_addr_list, + cookie, 0); + + fprintf(stderr, "c_client: erl_connect_xinit(): %d\n", ires); + + fd = erl_connect(peer_node); + fprintf(stderr, "c_client: erl_connect(): %d\n", fd); + + if (fd >= 0) + break; + fprintf(stderr, "c_client: cannot connect, retrying\n"); + } + if (fd < 0) { + fprintf(stderr, "c_client: cannot connect, exiting\n"); + done(1); + } + env = CORBA_Environment_alloc(INBUFSZ, OUTBUFSZ); + env->_fd = fd; + strcpy(env->_regname, peer_process_name); + env->_to_pid = NULL; + env->_from_pid = &pid; + + strcpy(pid.node, this_node); + pid.num = fd; + pid.serial = 0; + pid.creation = 0; + + my_gettimeofday(&start); + tres = test_func(env); /* Call test case */ + my_gettimeofday(&stop); + showtime(&start, &stop); + erl_close_connection(fd); + + printf("c_client: env->_inbuf before : %d\n", INBUFSZ); + printf("c_client: env->_outbuf before : %d\n", OUTBUFSZ); + printf("c_client: env->_inbuf after : %d\n", env->_inbufsz); + printf("c_client: env->_outbuf after : %d\n", env->_outbufsz); + + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + done(tres); +} + +static void usage() +{ + fprintf(stderr, "Usage: %s [-help] -this-node-name <name> " + "-peer-node <nodename> -peer-process-name <name> " + "-cookie <cookie> -test-case <test case name>\n", progname); + fprintf(stderr, "Example:\n %s -this-node-name kalle " + "-peer-node olle@home -peer-process-name idltest " + "-cookie oa678er -test-case octet_test\n", progname); +} + +static void done(int r) +{ +#ifdef __WIN32__ + WSACleanup(); +#endif + exit(r); +} + + +/* TESTS */ + +static int void_test(IC_Env *env) +{ + fprintf(stdout, "\n======== m_i_void test ======\n\n"); + m_i_void_test(NULL,env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(1); +} + +static int long_test(IC_Env *env) +{ + long l = 4711, lo, lr; + + fprintf(stdout, "\n======== m_i_long test ======\n\n"); + lr = m_i_long_test(NULL, l, &lo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(l == lo && l == lr); + if (l != lo) + fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n", l, lo); + if (l != lr) + fprintf(stdout, " result error, sent: %ld, got: %ld\n", l, lr); + return -1; +} + +static int long_long_test(IC_Env *env) +{ + CORBA_long_long ll = 4711, llo, llr; + + fprintf(stdout, "\n======== m_i_longlong test ======\n\n"); + llr = m_i_longlong_test(NULL, ll, &llo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ll == llo && ll == llr); + if (ll != llo) + fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n", + ll, llo); + if (ll != llr) + fprintf(stdout, " result error, sent: %ld, got: %ld\n", ll, llr); + return -1; +} + +static int unsigned_short_test(IC_Env *env) +{ + unsigned short x, y = 2, z; + + fprintf(stdout, "\n======== m_i_ushort test ======\n\n"); + x = m_i_ushort_test(NULL, y, &z, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(y == z && y == x); + if (y != z) + fprintf(stdout, " out parameter error, sent: %d, got: %d\n", y, z); + if (y != x) + fprintf(stdout, " result error, sent: %d, got: %d\n", y, x); + return -1; +} + + +static int unsigned_long_test(IC_Env *env) +{ + unsigned long ul = 5050, ulo, ulr; + + fprintf(stdout, "\n======== m_i_ulong test ======\n\n"); + ulr = m_i_ulong_test(NULL, ul, &ulo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ul == ulo && ul == ulr); + if (ul != ulo) + fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n", + ul, ulo); + if (ul != ulr) + fprintf(stdout, " result error, sent: %lu, got: %lu\n", ul, ulr); + return -1; +} + +/* + * Note: CORBA_unsigned_long_long is in fact a plain long. + */ +static int unsigned_long_long_test(IC_Env *env) +{ + CORBA_unsigned_long_long ull = 5050, ullo, ullr; + + fprintf(stdout, "\n======== m_i_ulonglong test ======\n\n"); + ullr = m_i_ulonglong_test(NULL, ull, &ullo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ull == ullo && ull == ullr); + if (ull != ullo) + fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n", + ull, ullo); + if (ull != ullr) + fprintf(stdout, " result error, sent: %lu, got: %lu\n", + ull, ullr); + return -1; +} + +static int double_test(IC_Env *env) +{ + double d = 12.1212, db, dr; + + fprintf(stdout, "\n======== m_i_double test ======\n\n"); + dr = m_i_double_test(NULL, d, &db, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(d == db && d == dr); + if (d != db) + fprintf(stdout, " out parameter error, sent: %f, got: %f\n", d, db); + if (d != dr) + fprintf(stdout, " result error, sent: %f, got: %f\n", d, dr); + return -1; +} + +static int char_test(IC_Env *env) +{ + char c = 'g', co, cr; + + /* char test */ + fprintf(stdout, "\n======== m_i_char test ======\n\n"); + cr = m_i_char_test(NULL, c, &co, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(c == co && c == cr); + if (c !=co) + fprintf(stdout, " out parameter error, sent: %c, got: %c\n", c, co); + if (c != cr) + fprintf(stdout, " result error, sent: %c, got: %c\n", c, cr); + return -1; +} + +static int wchar_test(IC_Env *env) +{ + CORBA_wchar wc = 103, wco, wcr; + + fprintf(stdout, "\n======== m_i_wchar test ======\n\n"); + wcr = m_i_wchar_test(NULL, wc, &wco, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(wc == wco && wc == wcr); + if (wc != wco) + fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n", + wc, wco); + if (wc != wcr) + fprintf(stdout, " result error, sent: %lu, got: %lu\n", + wc, wcr); + return -1; +} + +static int octet_test(IC_Env *env) +{ + char o ='r', oo, or; + + fprintf(stdout, "\n======== m_i_octet test ======\n\n"); + or = m_i_octet_test(NULL, o, &oo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(o == oo && o == or); + if (o != oo) + fprintf(stdout, " out parameter error, sent: %c, got: %c\n", o, oo); + if (o != or) + fprintf(stdout, " result error, sent: %c, got: %c\n", o, or); + return -1; +} + +static int bool_test(IC_Env *env) +{ + unsigned char i = 0, io, ir; + + fprintf(stdout, "\n======== m_i_bool test ======\n\n"); + ir = m_i_bool_test(NULL, i, &io, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(i == io && i == ir); + if (i != io) + fprintf(stdout, " out parameter error, sent: %d, got: %d\n", i, io); + if (i != ir) + fprintf(stdout, " result error, sent: %d, got: %d\n", i, ir); + return -1; +} + +static int struct_test(IC_Env *env) +{ + m_b b = {4711, 'a'}, bo, br; + + fprintf(stdout, "\n======== m_i_struct test ======\n\n"); + br = m_i_struct_test(NULL, &b, &bo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_b(&b, &bo) && cmp_b(&b, &br)); + if (!cmp_b(&b, &bo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_b(&b); + fprintf(stdout, " got:\n"); + print_b(&bo); + fprintf(stdout, "\n"); + } + if (!cmp_b(&b, &br)) { + fprintf(stdout, " result error, sent:\n"); + print_b(&b); + fprintf(stdout, " got:\n"); + print_b(&br); + fprintf(stdout, "\n"); + } + return -1; +} + +static int struct2_test(IC_Env *env) +{ + m_es esi = {m_peach, 5050}, eso, esr; + + fprintf(stdout, "\n======== m_i_struct2 test ======\n\n"); + esr = m_i_struct2_test(NULL, &esi, &eso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_es(&esi, &eso) && cmp_es(&esi, &esr)); + if (!cmp_es(&esi, &eso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_es(&esi); + fprintf(stdout, " got:\n"); + print_es(&eso); + fprintf(stdout, "\n"); + } + if (!cmp_es(&esi, &esr)) { + fprintf(stdout, " result error, sent:\n"); + print_es(&esi); + fprintf(stdout, " got:\n"); + print_es(&esr); + fprintf(stdout, "\n"); + } + return -1; +} + + +static int seq1_test(IC_Env *env) +{ + m_bseq bs, *bso, *bsr; + + m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}}; + bs._length = 3; + bs._buffer = ba; + + fprintf(stdout, "\n======== m_i_seq1 test ======\n\n"); + bsr = m_i_seq1_test(NULL, &bs, &bso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_bseq(&bs, bso) && cmp_bseq(&bs, bsr)); + if (!cmp_bseq(&bs, bso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_bseq(&bs); + fprintf(stdout, " got:\n"); + print_bseq(bso); + fprintf(stdout, "\n"); + } + if (!cmp_bseq(&bs, bsr)) { + fprintf(stdout, " result error, sent:\n"); + print_bseq(&bs); + fprintf(stdout, " got:\n"); + print_bseq(bsr); + fprintf(stdout, "\n"); + } + CORBA_free(bso); + CORBA_free(bsr); + return -1; +} + +static int seq2_test(IC_Env *env) +{ + m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}}; + m_a a; + m_a aa[2]; + m_aseq as, *aso, *asr; + + a.l = 9999; + a.y._length = 3; + a.y._buffer = ba; + a.d = 66.89898989; + + aa[0] = a; + aa[1] = a; + as._length = 2; + as._buffer = aa; + + fprintf(stdout, "\n======== m_i_seq2 test ======\n\n"); + asr = m_i_seq2_test(NULL, &as, &aso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_aseq(&as, aso) && cmp_aseq(&as, asr)); + if (!cmp_aseq(&as, aso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_aseq(&as); + fprintf(stdout, " got:\n"); + print_aseq(aso); + fprintf(stdout, "\n"); + } + if (!cmp_aseq(&as, asr)) { + fprintf(stdout, " result error, sent:\n"); + print_aseq(&as); + fprintf(stdout, " got:\n"); + print_aseq(asr); + fprintf(stdout, "\n"); + } + CORBA_free(aso); + CORBA_free(asr); + return -1; +} + +static int seq3_test(IC_Env *env) +{ + m_lseq lsi, *lso, *lsr; + long al[500]; + int i=0; + + for (i = 0; i < 500; i++) + al[i]=i; + lsi._length = 500; + lsi._buffer = al; + + fprintf(stdout, "\n======== m_i_seq3 test ======\n\n"); + lsr = m_i_seq3_test(NULL, &lsi, &lso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_lseq(&lsi, lso) && cmp_lseq(&lsi, lsr)); + if (!cmp_lseq(&lsi, lso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_lseq(&lsi); + fprintf(stdout, " got:\n"); + print_lseq(lso); + fprintf(stdout, "\n"); + } + if (!cmp_lseq(&lsi, lsr)) { + fprintf(stdout, " result error, sent:\n"); + print_lseq(&lsi); + fprintf(stdout, " got:\n"); + print_lseq(lsr); + fprintf(stdout, "\n"); + } + CORBA_free(lso); + CORBA_free(lsr); + return -1; +} + +static int seq4_test(IC_Env *env) +{ + char *stra0[3] = {"a", "long", "time"}; + char *stra1[3] = {"ago", "there", "was"}; + char *stra2[3] = {"a", "buggy", "compiler"}; + m_sstr3 str3s[3] = {{3, 3, stra0}, {3, 3, stra1}, {3, 3, stra2}}; + m_ssstr3 str3ssi = {3, 3, str3s}; + m_ssstr3 *str3sso, *str3ssr; + + fprintf(stdout, "\n======== m_i_seq4 test ======\n\n"); + str3ssr = m_i_seq4_test(NULL, &str3ssi, &str3sso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_ssstr3(&str3ssi, str3sso) && + cmp_ssstr3(&str3ssi, str3ssr)); + if (!cmp_ssstr3(&str3ssi, str3sso)){ + fprintf(stdout, " out parameter error, sent:\n"); + print_ssstr3(&str3ssi); + fprintf(stdout, " got:\n"); + print_ssstr3(str3sso); + fprintf(stdout, "\n"); + } + if (!cmp_ssstr3(&str3ssi, str3ssr)) { + fprintf(stdout, " result error, sent:\n"); + print_ssstr3(&str3ssi); + fprintf(stdout, " got:\n"); + print_ssstr3(str3ssr); + fprintf(stdout, "\n"); + } + CORBA_free(str3sso); + CORBA_free(str3ssr); + return -1; +} + +static int seq5_test(IC_Env *env) +{ + m_arr3 arr3a[3] = { + {4711, 18931947, 3}, + {4711, 18931947, 3}, + {4711, 18931947, 3}}; + m_sarr3 arr3sa[3] = {{3, 3, arr3a}, {3, 3, arr3a}, {3, 3, arr3a}}; + m_ssarr3 arr3ssi = {3, 3, arr3sa}; + m_ssarr3 *arr3sso; + m_ssarr3 *arr3ssr; + + fprintf(stdout, "\n======== m_i_seq5 test ======\n\n"); + arr3ssr = m_i_seq5_test(NULL, &arr3ssi, &arr3sso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_ssarr3(&arr3ssi, arr3sso) && + cmp_ssarr3(&arr3ssi, arr3ssr)); + if (!cmp_ssarr3(&arr3ssi, arr3sso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_ssarr3(&arr3ssi); + fprintf(stdout, " got:\n"); + print_ssarr3(arr3sso); + fprintf(stdout, "\n"); + } + if (!cmp_ssarr3(&arr3ssi, arr3ssr)) { + fprintf(stdout, " result error, sent:\n"); + print_ssarr3(&arr3ssi); + fprintf(stdout, " got:\n"); + print_ssarr3(arr3ssr); + fprintf(stdout, "\n"); + } + CORBA_free(arr3sso); + CORBA_free(arr3ssr); + return -1; +} + +static int array1_test(IC_Env *env) +{ + int i; + long al[500]; + m_arr1 alo; + m_arr1_slice* alr; + + for (i = 0; i < 500; i++) + al[i]=i; + + fprintf(stdout, "\n======== m_i_array1 test ======\n\n"); + alr = m_i_array1_test(NULL, al, alo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_arr1(al, alo) && cmp_arr1(al, alr)); + if (!cmp_arr1(al, alo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_arr1(al); + fprintf(stdout, " got:\n"); + print_arr1(alo); + fprintf(stdout, "\n"); + } + if (!cmp_arr1(al,alr)) { + fprintf(stdout, " result error, sent:\n"); + print_arr1(al); + fprintf(stdout, " got:\n"); + print_arr1(alr); + fprintf(stdout, "\n"); + } + free(alo); + free(alr); + return -1; +} + +static int array2_test(IC_Env *env) +{ + long dl[2][3] = {{11, 2, 7}, {22, 8 ,13}}; + m_dd dlo; + m_dd_slice* dlr; + + fprintf(stdout, "\n======== m_i_array2 test ======\n\n"); + dlr = m_i_array2_test(NULL, dl, dlo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_dd(dl,dlo) && cmp_dd(dl,dlr)); + if (!cmp_dd(dl,dlo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_dd(dl); + fprintf(stdout, " got:\n"); + print_dd(dlo); + fprintf(stdout, "\n"); + } + if (!cmp_dd(dl,dlr)) { + fprintf(stdout, " result error, sent:\n"); + print_dd(dl); + fprintf(stdout, " got:\n"); + print_dd(dlr); + fprintf(stdout, "\n"); + } + free(*dlr); + return -1; +} + +static int enum_test(IC_Env *env) +{ + m_fruit ei = m_banana, eo, er; + + fprintf(stdout, "\n======== m_i_enum test ======\n\n"); + er = m_i_enum_test(NULL, ei, &eo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ei == eo && ei == er); + if (ei != eo) + fprintf(stdout, " out parameter error, sent: %d, got: %d\n", ei, eo); + if (ei != er) + fprintf(stdout, " result error, sent: %d, got: %d\n", ei, er); + return -1; +} + +static int string1_test(IC_Env *env) +{ + char* si = longtext; + char* so; + char* sr; + + fprintf(stdout, "\n======== m_i_string1 test ======\n\n"); + sr = m_i_string1_test(NULL, si, &so, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, sr)); + if (!cmp_str(si, so)) + fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so); + if (!cmp_str(si, sr)) + fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr); + CORBA_free(so); + CORBA_free(sr); + return -1; +} + +static int string2_test(IC_Env *env) +{ + char* sa[3] = {"hello", "foo", "bar"}; + m_sseq ssi = {3, 3, sa}; + m_sseq *sso, *ssr; + + fprintf(stdout, "\n======== m_i_string2 test ======\n\n"); + ssr = m_i_string2_test(NULL, &ssi, &sso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_sseq(&ssi, sso) && cmp_sseq(&ssi, sso)); + if (!cmp_sseq(&ssi, sso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_sseq(&ssi); + fprintf(stdout, "got:\n"); + print_sseq(sso); + } + if (!cmp_sseq(&ssi, ssr)) { + fprintf(stdout, " result error, sent:\n"); + print_sseq(&ssi); + fprintf(stdout, "got:\n"); + print_sseq(ssr); + } + CORBA_free(sso); + CORBA_free(ssr); + return -1; +} + +static int string3_test(IC_Env *env) +{ + char* si = longtext; + char* so; + char* sr; + + fprintf(stdout, "\n======== m_i_string3 test ======\n\n"); + sr = m_i_string3_test(NULL, si, &so, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, so)); + if (!cmp_str(si, so)) + fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so); + if (!cmp_str(si, sr)) + fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr); + CORBA_free(so); + CORBA_free(sr); + return -1; +} + +static int string4_test(IC_Env *env) +{ + char as1[100] = "a string", as2[200] = "help", as3[200] = "hello there"; + m_strRec stri = { 1, /* dd */ + as1, /* str4 */ + {{'a', 'k'}, {'z', 'g'}, {'n', 'q'}}, /* str7 */ + {3, 3, "buf"}, /* str5 */ + as2, /* str6 */ + {'m', 'f', 'o'}, /* str8 */ + as3, /* str9 */ + {3, 3, "stu"} /* str10 */ + }; + m_strRec *stro, *strr; + + fprintf(stdout, "\n======== m_i_string4 test ======\n\n"); + strr = m_i_string4_test(NULL, &stri, &stro, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_strRec(&stri,stro) && cmp_strRec(&stri,strr)); + if (!cmp_strRec(&stri,stro)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_strRec(&stri); + fprintf(stdout, " got:\n"); + print_strRec(stro); + fprintf(stdout, "\n"); + } + if (!cmp_strRec(&stri,strr)) { + fprintf(stdout, " result error, sent:\n"); + print_strRec(&stri); + fprintf(stdout, " got:\n"); + print_strRec(strr); + fprintf(stdout, "\n"); + } + CORBA_free(stro); + CORBA_free(strr); + return -1; +} + + +static int pid_test(IC_Env *env) +{ + erlang_pid pid = {"", 7, 0, 0}, pido, pidr; + + strcpy(pid.node, this_node), /* this currently running node */ + fprintf(stdout, "\n======== m_i_pid test ======\n\n"); + pidr = m_i_pid_test(NULL, &pid, &pido, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_pid(&pid, &pido) && cmp_pid(&pid, &pidr)); + if (!cmp_pid(&pid, &pido)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_pid(&pid); + fprintf(stdout, "got:\n"); + print_pid(&pido); + } + if (!cmp_pid(&pid, &pidr)) { + fprintf(stdout, " result error, sent:\n"); + print_pid(&pid); + fprintf(stdout, "got:\n"); + print_pid(&pidr); + } + return -1; +} + +static int port_test(IC_Env *env) +{ + erlang_port porti = {"node", 5, 1}, porto, portr; + + fprintf(stdout, "\n======== m_i_port test ======\n\n"); + portr = m_i_port_test(NULL, &porti, &porto, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_port(&porti, &porto) && cmp_port(&porti, &portr)); + if (!cmp_port(&porti, &porto)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_port(&porti); + fprintf(stdout, "got:\n"); + print_port(&porto); + } + if (!cmp_port(&porti, &portr)) { + fprintf(stdout, " result error, sent:\n"); + print_port(&porti); + fprintf(stdout, "got:\n"); + print_port(&portr); + } + return -1; +} + +static int ref_test(IC_Env *env) +{ + erlang_ref refi = { "node1", 3, {1, 2, 3}, 1}, + refo, refr; + + fprintf(stdout, "\n======== m_i_ref test ======\n\n"); + refr = m_i_ref_test(NULL, &refi, &refo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_ref(&refi, &refo) && cmp_ref(&refi, &refr)); + if (!cmp_ref(&refi, &refo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_ref(&refi); + fprintf(stdout, "got:\n"); + print_ref(&refo); + } + if (!cmp_ref(&refi, &refr)) { + fprintf(stdout, " result error, sent:\n"); + print_ref(&refi); + fprintf(stdout, "got:\n"); + print_ref(&refr); + } + return -1; +} + +static int term_test(IC_Env *env) +{ + ETERM *ti, *to, *tr; + + ti = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"); + + fprintf(stdout, "\n======== m_i_term test ======\n\n"); + tr = m_i_term_test(NULL, ti, &to, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(erl_match(ti, to) && erl_match(ti, tr)); + if (!erl_match(ti, to)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_term(ti); + fprintf(stdout, "got:\n"); + print_term(to); + } + if (!erl_match(ti, tr)) { + fprintf(stdout, " result error, sent:\n"); + print_term(ti); + fprintf(stdout, "got:\n"); + print_term(tr); + } + erl_free_term(ti); + erl_free_term(to); + erl_free_term(tr); + return -1; +} + +static int typedef_test(IC_Env *env) +{ + m_banan mbi, mbo; /* erlang_port */ + m_apa mai; /* ETERM* */ + m_apa mao = NULL; + long tl; + + strcpy(mbi.node,"node"); + mbi.id = 15; + mbi.creation = 1; + + fprintf(stdout, "\n======== m_i_typedef test ======\n\n"); + mai = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"); + tl = m_i_typedef_test(NULL, mai, &mbi, &mao, &mbo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(erl_match(mai, mao) && cmp_port(&mbi, &mbo) && tl == 4711); + if (!erl_match(mai, mao)) { + fprintf(stdout, " out parameter error (term), sent:\n"); + print_term(mai); + fprintf(stdout, "got:\n"); + print_term(mao); + } + if (!cmp_port(&mbi, &mbo)) { + fprintf(stdout, " out parameter error (port), sent:\n"); + print_port(&mbi); + fprintf(stdout, "got:\n"); + print_port(&mbo); + } + if (tl != 4711) { + fprintf(stdout, " result error, sent: 4711, got %ld\n", tl); + } + erl_free_term(mai); + erl_free_term(mao); + return -1; +} + +static int inline_sequence_test(IC_Env *env) +{ + int i; + long al[500]; + m_s isi = {4711, {500, 10, al}}, + *iso, *isr; + + for (i = 0; i < 500; i++) + al[i]=i; + fprintf(stdout, "\n======== m_i_inline_sequence test ======\n\n"); + isr = m_i_inline_sequence_test(NULL, &isi, &iso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_s(&isi, iso) && cmp_s(&isi, isr)); + if (!cmp_s(&isi, iso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_s(&isi); + fprintf(stdout, "got:\n"); + print_s(iso); + } + if (!cmp_s(&isi, isr)) { + fprintf(stdout, " result error, sent:\n"); + print_s(&isi); + fprintf(stdout, "got:\n"); + print_s(isr); + } + CORBA_free(iso); + CORBA_free(isr); + return -1; +} + +static int term_sequence_test(IC_Env *env) +{ + ETERM* et_array[4] = { + erl_format("[{apa, 1, 23}, \"string\", {1.23, 45}]"), + erl_format("[{banan, 1, 23}, \"string\", {1.23, 45}]"), + erl_format("[{apelsin, 1, 23}, \"string\", {1.23, 45}]"), + erl_format("[{mango, 1, 23}, \"string\", {1.23, 45}]")}; + m_etseq etsi = {4, 4, et_array}, *etso, *etsr; + + fprintf(stdout, "\n======== m_i_term_sequence test ======\n\n"); + etsr = m_i_term_sequence_test(NULL, &etsi, &etso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_etseq(&etsi, etso) && cmp_etseq(&etsi, etsr)); + if (!cmp_etseq(&etsi, etso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_etseq(&etsi); + fprintf(stdout, "got:\n"); + print_etseq(etso); + } + if (!cmp_etseq(&etsi, etsr)) { + fprintf(stdout, " result error, sent:\n"); + print_etseq(&etsi); + fprintf(stdout, "got:\n"); + print_etseq(etsr); + } + free_etseq_buf(&etsi); + free_etseq_buf(etso); + free_etseq_buf(etsr); + CORBA_free(etso); + CORBA_free(etsr); + return -1; +} + +static int term_struct_test(IC_Env *env) +{ + m_et eti = { erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"), + 121212 }; + m_et eto, etr; + + fprintf(stdout, "\n======== m_i_term_struct test ======\n\n"); + etr = m_i_term_struct_test(NULL, &eti, &eto, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_et(&eti, &eto) && cmp_et(&eti, &etr)); + if (!cmp_et(&eti, &eto)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_et(&eti); + fprintf(stdout, "got:\n"); + print_et(&eto); + } + if (!cmp_et(&eti, &etr)) { + fprintf(stdout, " result error, sent:\n"); + print_et(&eti); + fprintf(stdout, "got:\n"); + print_et(&etr); + } + free_et(&eti); + free_et(&eto); + free_et(&etr); + return -1; +} + +static int wstring1_test(IC_Env *env) +{ + CORBA_wchar wsi[] = {100, 101, 102, 103, 104, 0}, *wso, *wsr; + + fprintf(stdout, "\n======== m_i_wstring1 test ======\n\n"); + wsr = m_i_wstring1_test(NULL, wsi, &wso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_wstr(wsi, wso) && cmp_wstr(wsi, wsr)); + if (!cmp_wstr(wsi, wso)) { + fprintf(stdout, " out parameter error, sent: \n"); + print_wstr(wsi); + fprintf(stdout, "got:\n"); + print_wstr(wso); + } + if (!cmp_wstr(wsi, wsr)) { + fprintf(stdout, " result error, sent: \n"); + print_wstr(wsi); + fprintf(stdout, "got:\n"); + print_wstr(wsr); + } + CORBA_free(wso); + CORBA_free(wsr); + return -1; +} + +/* Compare functions */ +static int cmp_aseq(m_aseq *a1, m_aseq *a2) +{ + int i; + + if (a1->_length != a2->_length) + return 0; + for (i = 0; i < a1->_length; i++) + if (cmp_a(&(a1->_buffer[i]), &(a2->_buffer[i])) == 0) + return 0; + return 1; +} + +static int cmp_a(m_a *a1, m_a *a2) +{ + return a1->l == a2->l && + a1->d == a2->d && + cmp_bseq(&a1->y, &a2->y); +} + +static int cmp_bseq(m_bseq *b1, m_bseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (cmp_b(&(b1->_buffer[i]), &(b2->_buffer[i])) == 0) + return 0; + return 1; +} + +static int cmp_b(m_b *b1, m_b *b2) +{ + return b1->l == b2->l && b1->c == b2->c; +} + +static int cmp_lseq(m_lseq *b1, m_lseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (b1->_buffer[i] != b2->_buffer[i]) + return 0; + return 1; +} + +static int cmp_etseq(m_etseq *b1, m_etseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (!erl_match(b1->_buffer[i], b2->_buffer[i])) + return 0; + return 1; +} + +static int cmp_et(m_et* b1, m_et *b2) +{ + return erl_match(b1->e, b2->e) && b1->l == b2->l; +} + +static int cmp_es(m_es *b1, m_es *b2) +{ + return b1->f == b2->f && b1->l == b2->l; +} + +static int cmp_arr1(m_arr1 b1, m_arr1 b2) +{ + int i; + + for (i = 0; i < 500; i++) + if (b1[i] != b2[i]) + return 0; + return 1; +} + +static int cmp_dd(m_dd b1, m_dd b2) +{ + + int i, j; + + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + if (b1[i][j] != b2[i][j]) + return 0; + return 1; +} + + + +static int cmp_strRec(m_strRec *b1, m_strRec *b2) +{ + int i, j; + + if (b1->bb != b2->bb) + return 0; + if (!cmp_str(b1->str4,b2->str4)) + return 0; + if (b1->str5._length != b2->str5._length) + return 0; + for (j = 0; j < b1->str5._length; j++) + if (b1->str5._buffer[j] != b2->str5._buffer[j]) + return 0; + if (!cmp_str(b1->str6,b2->str6)) + return 0; + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + if (b1->str7[i][j] != b2->str7[i][j]) + return 0; + for (j = 0; j < 3; j++) + if (b1->str8[j] != b2->str8[j]) + return 0; + if (!cmp_str(b1->str9,b2->str9)) + return 0; + if (b1->str10._length != b2->str10._length) + return 0; + for (j = 0; j < b1->str10._length; j++) + if (b1->str10._buffer[j] != b2->str10._buffer[j]) + return 0; + return 1; +} + + +static int cmp_sseq(m_sseq *b1, m_sseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (!cmp_str(b1->_buffer[i], b2->_buffer[i])) + return 0; + return 1; +} + + +static int cmp_pid(erlang_pid *p1, erlang_pid *p2) +{ + return cmp_str(p1->node,p2-> node) && + p1->num == p2->num && + p1->serial == p2->serial && + p1->creation == p2->creation; +} + +static int cmp_port(erlang_port *p1, erlang_port *p2) +{ + return cmp_str(p1->node,p2-> node) && p1->id == p2->id; +} + +static int cmp_ref(erlang_ref *p1, erlang_ref *p2) +{ + return cmp_str(p1->node, p2->node) && + p1->len == p2->len && + (p1->len < 1 || p1->n[0] == p2->n[0]) && + (p1->len < 2 || p1->n[1] == p2->n[1]) && + (p1->len < 3 || p1->n[2] == p2->n[2]); +} + +static int cmp_s(m_s *b1, m_s *b2) +{ + int i; + + if (b1->l != b2->l) + return 0; + if (b1->sl._length != b2->sl._length) + return 0; + for (i = 0; i < b1->sl._length; i++) + if (b1->sl._buffer[i] != b2->sl._buffer[i]) + return 0; + return 1; +} + + +static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2) +{ + int i,j; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) { + if (b1->_buffer[i]._length != b2->_buffer[i]._length) + return 0; + for (j = 0; j < b1->_buffer[i]._length; j++) + if (!cmp_str(b1->_buffer[i]._buffer[j], + b2->_buffer[i]._buffer[j])) + return 0; + } + return 1; +} + + + +static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) { + if (!cmp_sarr3(&b1->_buffer[i], &b2->_buffer[i])) + return 0; + } + return 1; +} + +static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) { + if (!cmp_arr3(b1->_buffer[i], b2->_buffer[i])) + return 0; + } + return 1; +} + +static int cmp_arr3(m_arr3 b1, m_arr3 b2) +{ + int i; + + for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++) { + if (b1[i] != b2[i]) + return 0; + } + return 1; +} + +/* Print functions */ +static void print_aseq(m_aseq *a) +{ + int i; + fprintf(stdout, "\nm_aseq size: %ld --------\n", a->_length); + for (i = 0; i < a->_length; i++) + print_a(&(a->_buffer[i])); +} + +static void print_a(m_a *a) +{ + fprintf(stdout, "\nm_a --------\n l: %ld\n d:%f\n", a->l, a->d); + print_bseq(&a->y); +} + +static void print_bseq(m_bseq *b) +{ + int i; + + fprintf(stdout, "\nm_bseq size: %ld --------\n",b->_length); + for (i = 0; i < b->_length; i++) + print_b(&(b->_buffer[i])); +} + +static void print_lseq(m_lseq *b) +{ + int i; + + fprintf(stdout, "\nm_lseq size: %ld --------\n",b->_length); + for (i = 0; i < b->_length; i++) + fprintf(stdout, "[%d]: %ld\n", i, b->_buffer[i]); +} + +static void print_b(m_b *b) +{ + fprintf(stdout, "\nm_b --------\n l: %ld\n c: %c\n", b->l, b->c); +} + + +static void print_etseq(m_etseq *b) +{ + int i; + + for (i = 0; i < b->_length; i++) { + fprintf(stdout, "[%d]:\n", i); + erl_print_term(stdout, b->_buffer[i]); + } +} + + +static void print_et(m_et* b) +{ + fprintf(stdout, "\net struct --------\n"); + erl_print_term(stdout, b->e); + fprintf(stdout, "long: %ld\n", b->l); + fprintf(stdout, "\n--------\n"); +} + +static void print_es(m_es *b) +{ + fprintf(stdout, "\nm_es --------\n f: %d\n l: %ld\n", b->f, b->l); +} + + +static void print_arr1(long a[10]) +{ + int i; + + for (i = 0; i < 10; i++) + fprintf(stdout, "\n[%d]: %ld\n", i, a[i]); +} + +static void print_dd(long a[2][3]) +{ + int i, j; + + fprintf(stdout, "\nlong dd[2][3] --------\n"); + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + fprintf(stdout, "\n[%d][%d]: %ld\n", i, j, a[i][j]); +} + + +static void print_strRec(m_strRec* sr) +{ + int i, j; + + fprintf(stdout, "\nboolean bb : %d\n",sr->bb); + fprintf(stdout, "string str4 : %s\n",sr->str4); + fprintf(stdout, "str7[2][3] :\n"); + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + fprintf(stdout, "str7[%d][%d]: %ld\n", i, j, sr->str7[i][j]); + fprintf(stdout, "str5._length : %ld\n",sr->str5._length); + for (j = 0; j < sr->str5._length; j++) + fprintf(stdout, "str5._buffer[%d]: %c\n", j, sr->str5._buffer[j]); + fprintf(stdout, "string str6 : %s\n",sr->str6); + fprintf(stdout, "str8 :\n"); + for (j = 0; j < 3; j++) + fprintf(stdout, "str8[%d]: %c\n", j, sr->str8[j]); + fprintf(stdout, "string str9 : %s\n",sr->str9); + fprintf(stdout, "str10._length : %ld\n",sr->str10._length); + for (j = 0; j < sr->str10._length; j++) + fprintf(stdout, "str10._buffer[%d]: %c\n", j, sr->str10._buffer[j]); +} + +static void print_sseq(m_sseq *b) +{ + int i; + + fprintf(stdout, "\nm_sseq size: %ld --------\n",b->_length); + for (i = 0; i < b->_length; i++) + fprintf(stdout, "%s\n", b->_buffer[i]); + +} + + +static void print_pid(erlang_pid *p) +{ + fprintf(stdout, "\nerlang_pid --------\n node: %s\n num: %d\n " + "serial: %d\n creation: %d\n", + p->node, p->num, p->serial, p->creation); +} + +static void print_port(erlang_port *p) +{ + fprintf(stdout, "\nerlang_port --------\n node: %s\n id: %d\n " + "creation: %d\n", p->node, p->id, p->creation); +} + +static void print_ref(erlang_ref *p) +{ + fprintf(stdout, "\nerlang_ref --------\n node: %s\n len: %d\n " + "n[0]: %d\n n[1]: %d\n n[2]: %d\n creation: %d\n", + p->node, p->len, p->n[0], p->n[1], p->n[2], p->creation); +} + +static void print_term(ETERM *t) +{ + fprintf(stdout, "\nETERM --------\n"); + erl_print_term(stdout, t); + fprintf(stdout, "\n--------\n"); +} + +static void print_s(m_s *p) +{ + int i; + + fprintf(stdout, "\n%ld\n", p->l); + for (i = 0; i < p->sl._length; i++) + fprintf(stdout, "\n[%d]: %ld\n", i, p->sl._buffer[i]); +} + + +static void print_ssstr3(m_ssstr3 *b1) +{ + int i,j; + + fprintf(stdout, "\nSSSTR3 --------\n"); + fprintf(stdout,"b1->_length = %ld\n",b1->_length); + for (i = 0; i < b1->_length; i++) { + fprintf(stdout,"\nb1->_buffer[%d]._length %ld\n", + i, b1->_buffer[i]._length); + for (j = 0; j < b1->_buffer[i]._length; j++) + fprintf(stdout,"b1->_buffer[%d]._buffer[%d] = %s\n", + i, j, b1->_buffer[i]._buffer[j]); + } + fprintf(stdout, "\n--------\n"); +} + +static void print_wstr(CORBA_wchar *ws) +{ + int i = 0; + + fprintf(stdout, "\nwstr --------\n"); + while (ws[i]) { + fprintf(stdout, "[%d]: %ld\n", i, ws[i]); + i++; + } + fprintf(stdout, "\n--------\n"); +} + + +static void print_ssarr3(m_ssarr3 *b1) +{ + int i; + + fprintf(stdout, "\nssarr3 --------\n"); + fprintf(stdout,"length: %ld\n",b1->_length); + fprintf(stdout, "buffer:\n"); + for (i = 0; i < b1->_length; i++) + print_sarr3(&b1->_buffer[i]); + fprintf(stdout, "\n--------\n"); +} + +static void print_sarr3(m_sarr3 *b1) +{ + int i; + + fprintf(stdout, "\nsarr3 --------\n"); + fprintf(stdout,"length: %ld\n",b1->_length); + fprintf(stdout, "buffer:\n"); + for (i = 0; i < b1->_length; i++) + print_arr3(b1->_buffer[i]); + fprintf(stdout, "\n--------\n"); +} + +static void print_arr3(m_arr3 b1) +{ + int i; + + fprintf(stdout, "\narr3 --------\n"); + for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++) + fprintf(stdout, "%ld ", b1[i]); + fprintf(stdout, "\n--------\n"); +} + +static void free_etseq_buf(m_etseq *b) +{ + int i; + + for (i = 0; i < b->_length; i++) + erl_free_term(b->_buffer[i]); +} + +static void free_et(m_et* b) +{ + erl_free_term(b->e); +} + +static void showtime(MyTimeval *start, MyTimeval *stop) +{ + MyTimeval elapsed; + + elapsed.tv_sec = stop->tv_sec - start->tv_sec; + elapsed.tv_usec = stop->tv_usec - start->tv_usec; + while (elapsed.tv_usec < 0) { + elapsed.tv_sec -= 1; + elapsed.tv_usec += 1000000; + } + fprintf(stderr,"%ld.%06ld seconds\n",elapsed.tv_sec, elapsed.tv_usec); +} + +static void my_gettimeofday(MyTimeval *tv) +#ifdef __WIN32__ +#define EPOCH_JULIAN_DIFF 11644473600i64 +{ + SYSTEMTIME t; + FILETIME ft; + LONGLONG lft; + + GetSystemTime(&t); + SystemTimeToFileTime(&t, &ft); + memcpy(&lft, &ft, sizeof(lft)); + tv->tv_usec = (long) ((lft / 10i64) % 1000000i64); + tv->tv_sec = (long) ((lft / 10000000i64) - EPOCH_JULIAN_DIFF); +} +#elif defined VXWORKS +{ + int rate = sysClkRateGet(); /* Ticks per second */ + unsigned long ctick = tickGet(); + tv->tv_sec = ctick / rate; /* secs since reboot */ + tv->tv_usec = ((ctick - (tv->tv_sec * rate))*1000000)/rate; +} +#else +{ + gettimeofday(tv, NULL); +} +#endif diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_erl_test.idl b/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_erl_test.idl new file mode 100644 index 0000000000..6d229c3ac1 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_SUITE_data/c_erl_test.idl @@ -0,0 +1,173 @@ + +// %CopyrightBegin% +// +// Copyright Ericsson AB 2003-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +#include "erlang.idl" + + +const short TestConst = 1; + +module m { + + const short TestConst = 2; + + struct b { + long l; + char c; + }; + + struct simple { + long l; + b b_t; + }; + + enum fruit {orange, banana, apple, peach, pear}; + + typedef sequence<long> lseq; + + typedef sequence<b> bseq; + + struct a { + long l; + bseq y; + double d; + }; + + typedef sequence<a> aseq; + + typedef sequence<string> sseq; + typedef string str; + typedef long myLong; + + typedef long arr1[500], dd[2][3]; + + typedef erlang::term apa; + typedef erlang::port banan; + + typedef sequence<erlang::term> etseq; + + struct s { + long l; + sequence<long> sl; + }; + + struct es { + fruit f; + myLong l; + }; + + struct et { + erlang::term e; + long l; + }; + + + typedef sequence<char> str1; + typedef string<12> str2; + typedef char str3[3]; + + typedef sequence<string> sstr3; // sequence of string + typedef sequence<sstr3> ssstr3; // sequence of sequences of strings + + typedef long arr3[3]; // array of long + typedef sequence<arr3> sarr3; // sequence of array + typedef sequence<sarr3> ssarr3; // sequence of sequnces of arrays of strings + + struct strRec{ + boolean bb; + string str4; + long str7[3][2]; + sequence<char> str5; + string<12> str6; + str3 str8; + str2 str9; + str1 str10; + }; + + + struct dyn { + long l; + sequence<long> sl; + }; + typedef dyn arr2[1][2]; + + + interface i { + + const short TestConst = 3; + + //arr2 suck(in arr2 x, out arr2 y ); + + ///////////////////////////////// attribute long l; + + // simple types + void void_test(); + long long_test(in long a, out long a1); + long long longlong_test(in long long a, out long long a1); + unsigned short ushort_test(in unsigned short a, out unsigned short a1); + unsigned long ulong_test(in unsigned long a, out unsigned long a1); + unsigned long long ulonglong_test(in unsigned long long a, out unsigned long long a1); + double double_test(in double a, out double a1); + char char_test(in char a, out char a1); + wchar wchar_test(in wchar a, out wchar a1); + octet octet_test(in octet a, out octet a1); + boolean bool_test(in boolean a, out boolean a1); + + // Seq. and struct tests + b struct_test(in b a, out b a1); + es struct2_test(in es a, out es a1); + //simple struct3_test(in simple x, out simple y); + bseq seq1_test(in bseq a, out bseq a1); + aseq seq2_test(in aseq a, out aseq a1); + lseq seq3_test(in lseq a, out lseq a1); + ssstr3 seq4_test(in ssstr3 a, out ssstr3 a1); + ssarr3 seq5_test(in ssarr3 a, out ssarr3 a1); + + // Array tests + arr1 array1_test(in arr1 a, out arr1 a1); + dd array2_test(in dd a, out dd a1); + + // enum test + fruit enum_test(in fruit a, out fruit a1); + + // string tests + string string1_test(in string a, out string a1); + wstring wstring1_test(in wstring a, out wstring a1); + sseq string2_test(in sseq a, out sseq a1); + str string3_test(in str a, out str a1); + strRec string4_test(in strRec a, out strRec a1); + + // Special erlang types + erlang::pid pid_test(in erlang::pid a, out erlang::pid a1); + erlang::port port_test(in erlang::port a, out erlang::port a1); + erlang::ref ref_test(in erlang::ref a, out erlang::ref a1); + erlang::term term_test(in erlang::term a, out erlang::term a1); + + // typedef test + long typedef_test(in apa a, in banan b, out apa a1, out banan b1); + + // inlined seq. test + s inline_sequence_test(in s a, out s a1); + + // term seq. test + etseq term_sequence_test(in etseq a, out etseq a1); + // term struct test + et term_struct_test(in et a, out et a1); + + }; + +}; diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/erl_server.erl b/lib/ic/test/c_client_erl_server_proto_SUITE_data/erl_server.erl new file mode 100644 index 0000000000..09358b7cf9 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_SUITE_data/erl_server.erl @@ -0,0 +1,28 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(erl_server). + +-export([run/0, stop/0]). + +run() -> + m_i:oe_create(). + +stop() -> + gen_server:cast(cidl_test, stop). diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/m_i_impl.erl b/lib/ic/test/c_client_erl_server_proto_SUITE_data/m_i_impl.erl new file mode 100644 index 0000000000..9f231de856 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_SUITE_data/m_i_impl.erl @@ -0,0 +1,161 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(m_i_impl). +-include("m.hrl"). + +-export([init/1, terminate/2, void_test/1, long_test/2, ushort_test/2, + longlong_test/2, ulong_test/2, ulonglong_test/2, + double_test/2, char_test/2, wchar_test/2, octet_test/2, + bool_test/2, struct_test/2, struct2_test/2, seq1_test/2, + seq2_test/2, seq3_test/2, seq4_test/2, seq5_test/2, + array1_test/2, array2_test/2, enum_test/2, string1_test/2, + string2_test/2, string3_test/2, string4_test/2, pid_test/2, + port_test/2, ref_test/2, term_test/2, typedef_test/3, + inline_sequence_test/2, '_set_l'/2, '_get_l'/1, + term_struct_test/2, term_sequence_test/2, wstring1_test/2]). + +-define(PRINTDEBUG(Case), + io:format("erl_server: case: ~p~n" + "erl_server: location: ~p~n", [Case, [?FILE, ?LINE]])). +-define(PRINTDEBUG2(Case, Msg), + io:format("erl_server: case: ~p~n" + "erl_server: Msg: ~p~n" + "erl_server: location: ~p~n", [Case, Msg, [?FILE, ?LINE]])). + +init(Env) -> + {ok, []}. + +terminate(F, R) -> + ok. + +'_get_l'(State) -> + ?PRINTDEBUG("_get_l"), + {reply, State, State}. +void_test(State) -> + ?PRINTDEBUG("void_test"), + {reply, ok, State}. + +'_set_l'(State, V) -> + ?PRINTDEBUG2("_set_l", V), + {reply, ok, V}. +ushort_test(State, V) -> + ?PRINTDEBUG2("ushort_test", V), + {reply, {V, V}, State}. +long_test(State, V) -> + ?PRINTDEBUG2("long_test", V), + {reply, {V, V}, State}. +longlong_test(State, V) -> + ?PRINTDEBUG2("longlong_test", V), + {reply, {V, V}, State}. +ulong_test(State, V) -> + ?PRINTDEBUG2("ulong_test", V), + {reply, {V, V}, State}. +ulonglong_test(State, V) -> + ?PRINTDEBUG2("ulonglong_test", V), + {reply, {V, V}, State}. +double_test(State, V) -> + ?PRINTDEBUG2("double_test", V), + {reply, {V, V}, State}. +char_test(State, V) -> + ?PRINTDEBUG2("char_test", V), + {reply, {V, V}, State}. +wchar_test(State, V) -> + ?PRINTDEBUG2("wchar_test", V), + {reply, {V, V}, State}. +octet_test(State, V) -> + ?PRINTDEBUG2("octet_test", V), + {reply, {V, V}, State}. +bool_test(State, V) -> + ?PRINTDEBUG2("bool_test", V), + {reply, {V, V}, State}. + +struct_test(State, V) -> + ?PRINTDEBUG2("struct_test", V), + {reply, {V, V}, State}. +struct2_test(State, V) -> + ?PRINTDEBUG2("struct2_test", V), + {reply, {V, V}, State}. +seq1_test(State, V) -> + ?PRINTDEBUG2("seq1_test", V), + {reply, {V, V}, State}. +seq2_test(State, V) -> + ?PRINTDEBUG2("seq2_test", V), + {reply, {V, V}, State}. +seq3_test(State, V) -> + ?PRINTDEBUG2("seq3_test", V), + {reply, {V, V}, State}. +seq4_test(State, V) -> + ?PRINTDEBUG2("seq4_test", V), + {reply, {V, V}, State}. +seq5_test(State, V) -> + ?PRINTDEBUG2("seq5_test", V), + {reply, {V, V}, State}. +array1_test(State, V) -> + ?PRINTDEBUG2("array1_test", V), + {reply, {V, V}, State}. +array2_test(State, V) -> + ?PRINTDEBUG2("array2_test", V), + {reply, {V, V}, State}. +enum_test(State, V) -> + ?PRINTDEBUG2("enum_test", V), + {reply, {V, V}, State}. +string1_test(State, V) -> + ?PRINTDEBUG2("string1_test", V), + {reply, {V, V}, State}. +string2_test(State, V) -> + ?PRINTDEBUG2("string2_test", V), + {reply, {V, V}, State}. +string3_test(State, V) -> + ?PRINTDEBUG2("string3_test", V), + {reply, {V, V}, State}. +string4_test(State, V) -> + ?PRINTDEBUG2("string4_test", V), + {reply, {V, V}, State}. +pid_test(State, V) -> + ?PRINTDEBUG2("pid_test", V), + {reply, {V, V}, State}. +port_test(State, V) -> + ?PRINTDEBUG2("port_test", binary_to_list(term_to_binary(V))), + {reply, {V, V}, State}. +ref_test(State, V) -> + ?PRINTDEBUG2("ref_test", binary_to_list(term_to_binary(V))), + {reply, {V, V}, State}. +term_test(State, V) -> + ?PRINTDEBUG2("term_test", V), + {reply, {V, V}, State}. +typedef_test(State, A, B) -> + ?PRINTDEBUG2("typedef_test", [A,B]), + {reply, {4711, A, B}, State}. +inline_sequence_test(State, V) -> + ?PRINTDEBUG2("inline_sequence_test", V), + {reply, {V, V}, State}. +term_sequence_test(State, V) -> + ?PRINTDEBUG2("term_sequence_test", V), + {reply, {V, V}, State}. +term_struct_test(State, V) -> + ?PRINTDEBUG2("term_struct_test", V), + {reply, {V, V}, State}. +wstring1_test(State, V) -> + ?PRINTDEBUG2("wstring1_test", V), + {reply, {V, V}, State}. + + + + diff --git a/lib/ic/test/c_client_erl_server_proto_SUITE_data/my.c b/lib/ic/test/c_client_erl_server_proto_SUITE_data/my.c new file mode 100644 index 0000000000..f8a3b28cc2 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_SUITE_data/my.c @@ -0,0 +1,50 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ + +#include "ic.h" +#include "m_i.h" + +int my_prepare_notification_encoding(CORBA_Environment *env) +{ + return oe_prepare_notification_encoding(env); +} + +int my_send_notification(CORBA_Environment *env) +{ + return oe_send_notification(env); +} + +int my_prepare_request_encoding(CORBA_Environment *env) +{ + return oe_prepare_request_encoding(env); +} + +int my_send_request_and_receive_reply(CORBA_Environment *env) +{ + return oe_send_request_and_receive_reply(env); +} + +int my_prepare_reply_decoding(CORBA_Environment *env) +{ + return oe_prepare_reply_decoding(env); +} + + + diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE.erl b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE.erl new file mode 100644 index 0000000000..595c5bf483 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE.erl @@ -0,0 +1,315 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +%%---------------------------------------------------------------------- +%% Purpose : Test suite for c-client/erl-server +%%---------------------------------------------------------------------- + +-module(c_client_erl_server_proto_tmo_SUITE). +-include("test_server.hrl"). + +-export([init_per_testcase/2, fin_per_testcase/2, + all/1, void_test/1, long_test/1, long_long_test/1, + unsigned_short_test/1, unsigned_long_test/1, + unsigned_long_long_test/1, double_test/1, char_test/1, + wchar_test/1, octet_test/1, bool_test/1, struct_test/1, + struct2_test/1, seq1_test/1, seq2_test/1, seq3_test/1, + seq4_test/1, seq5_test/1, array1_test/1, array2_test/1, + enum_test/1, string1_test/1, string2_test/1, string3_test/1, + string4_test/1, pid_test/1, port_test/1, ref_test/1, term_test/1, + typedef_test/1, inline_sequence_test/1, term_sequence_test/1, + term_struct_test/1, wstring1_test/1]). + +-define(DEFAULT_TIMEOUT, 20000). +-define(PORT_TIMEOUT, 15000). +-define(ERLANG_SERVER_NAME, idl_erlang_server). +-define(C_CLIENT_NODE_NAME, c_client_idl_test). + +%% Add/remove code path and watchdog before/after each test case. +%% +init_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:add_patha(DataDir), + + %% Since other test suites use the module m_i, we have + %% to make sure we are using the right m_i module. + code:purge(m_i), + code:load_file(m_i), + + WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:del_path(DataDir), + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of IC with a C-client and an Erlang generic server. " + "The communication is via Erlang distribution."; +all(suite) -> + [void_test, long_test, long_long_test, unsigned_short_test, + unsigned_long_test, unsigned_long_long_test, double_test, + char_test, wchar_test, octet_test, bool_test, struct_test, + struct2_test, seq1_test, seq2_test, seq3_test, seq4_test, + seq5_test, array1_test, array2_test, enum_test, string1_test, + string2_test, string3_test, string4_test, pid_test, port_test, + ref_test, term_test, typedef_test, inline_sequence_test, + term_sequence_test, term_struct_test, wstring1_test]. + + +array1_test(doc) -> ""; +array1_test(suite) -> []; +array1_test(Config) -> + do_test(array1_test, Config). + +array2_test(doc) -> ""; +array2_test(suite) -> []; +array2_test(Config) -> + do_test(array2_test, Config). + +bool_test(doc) -> ""; +bool_test(suite) -> []; +bool_test(Config) -> + do_test(bool_test, Config). + +char_test(doc) -> ""; +char_test(suite) -> []; +char_test(Config) -> + do_test(char_test, Config). + +double_test(doc) -> ""; +double_test(suite) -> []; +double_test(Config) -> + do_test(double_test, Config). + +enum_test(doc) -> ""; +enum_test(suite) -> []; +enum_test(Config) -> + do_test(enum_test, Config). + +inline_sequence_test(doc) -> ""; +inline_sequence_test(suite) -> []; +inline_sequence_test(Config) -> + do_test(inline_sequence_test, Config). + +long_long_test(doc) -> ""; +long_long_test(suite) -> []; +long_long_test(Config) -> + do_test(long_long_test, Config). + +long_test(doc) -> ""; +long_test(suite) -> []; +long_test(Config) -> + do_test(long_test, Config). + +octet_test(doc) -> ""; +octet_test(suite) -> []; +octet_test(Config) -> + do_test(octet_test, Config). + +pid_test(doc) -> ""; +pid_test(suite) -> []; +pid_test(Config) -> + do_test(pid_test, Config). + +port_test(doc) -> ""; +port_test(suite) -> []; +port_test(Config) -> + do_test(port_test, Config). + +ref_test(doc) -> ""; +ref_test(suite) -> []; +ref_test(Config) -> + do_test(ref_test, Config). + +seq1_test(doc) -> ""; +seq1_test(suite) -> []; +seq1_test(Config) -> + do_test(seq1_test, Config). + +seq2_test(doc) -> ""; +seq2_test(suite) -> []; +seq2_test(Config) -> + do_test(seq2_test, Config). + +seq3_test(doc) -> ""; +seq3_test(suite) -> []; +seq3_test(Config) -> + do_test(seq3_test, Config). + +seq4_test(doc) -> ""; +seq4_test(suite) -> []; +seq4_test(Config) -> + do_test(seq4_test, Config). + +seq5_test(doc) -> ""; +seq5_test(suite) -> []; +seq5_test(Config) -> + do_test(seq5_test, Config). + +string1_test(doc) -> ""; +string1_test(suite) -> []; +string1_test(Config) -> + do_test(string1_test, Config). + +string2_test(doc) -> ""; +string2_test(suite) -> []; +string2_test(Config) -> + do_test(string2_test, Config). + +string3_test(doc) -> ""; +string3_test(suite) -> []; +string3_test(Config) -> + do_test(string3_test, Config). + +string4_test(doc) -> ""; +string4_test(suite) -> []; +string4_test(Config) -> + do_test(string4_test, Config). + +struct2_test(doc) -> ""; +struct2_test(suite) -> []; +struct2_test(Config) -> + do_test(struct2_test, Config). + +struct_test(doc) -> ""; +struct_test(suite) -> []; +struct_test(Config) -> + do_test(struct_test, Config). + +term_sequence_test(doc) -> ""; +term_sequence_test(suite) -> []; +term_sequence_test(Config) -> + do_test(term_sequence_test, Config). + +term_struct_test(doc) -> ""; +term_struct_test(suite) -> []; +term_struct_test(Config) -> + do_test(term_struct_test, Config). + +term_test(doc) -> ""; +term_test(suite) -> []; +term_test(Config) -> + do_test(term_test, Config). + +typedef_test(doc) -> ""; +typedef_test(suite) -> []; +typedef_test(Config) -> + do_test(typedef_test, Config). + +unsigned_long_long_test(doc) -> ""; +unsigned_long_long_test(suite) -> []; +unsigned_long_long_test(Config) -> + do_test(unsigned_long_long_test, Config). + +unsigned_long_test(doc) -> ""; +unsigned_long_test(suite) -> []; +unsigned_long_test(Config) -> + do_test(unsigned_long_test, Config). + +unsigned_short_test(doc) -> ""; +unsigned_short_test(suite) -> []; +unsigned_short_test(Config) -> + do_test(unsigned_short_test, Config). + +void_test(doc) -> ""; +void_test(suite) -> []; +void_test(Config) -> + do_test(void_test, Config). + +wchar_test(doc) -> ""; +wchar_test(suite) -> []; +wchar_test(Config) -> + do_test(wchar_test, Config). + +wstring1_test(doc) -> ""; +wstring1_test(suite) -> []; +wstring1_test(Config) -> + do_test(wstring1_test, Config). + + +%% It is here that all tests really are done. +%% + +do_test(Case, Config) -> + %% Trap exits + process_flag(trap_exit, true), + %% Start the server + {ok, _Pid} = m_i:oe_create_link([], {local, ?ERLANG_SERVER_NAME}), + Node = atom_to_list(node()), + %% [NodeName, HostName] = string:tokens(Node, "@"), + DataDir = ?config(data_dir, Config), + %% io:format("~p: data directory: ~p~n", [?MODULE, DataDir]), + Cookie = atom_to_list(erlang:get_cookie()), + %% Start C-client node as a port program. + Cmd = filename:join([DataDir, "c_client"]) ++ + " -this-node-name " ++ atom_to_list(?C_CLIENT_NODE_NAME) ++ + " -peer-node " ++ Node ++ + " -peer-process-name " ++ atom_to_list(?ERLANG_SERVER_NAME) ++ + " -cookie " ++ Cookie ++ + " -test-case " ++ atom_to_list(Case), + Port = open_port({spawn, Cmd}, [exit_status, eof, stderr_to_stdout]), + Res = wait_for_completion(Port), + %% Kill off node if there was timeout + case Res of + {error, timeout} -> + catch rpc:cast(?C_CLIENT_NODE_NAME, erlang, halt, [1]); + _ -> + ok + end, + process_flag(trap_exit, false), + catch m_i:stop(?ERLANG_SERVER_NAME), + ok = Res. + + +%% Wait for eof *and* exit status, but return if exit status indicates +%% an error, or we have been waiting more than PORT_TIMEOUT seconds. +%% +wait_for_completion(Port) -> + wait_for_completion(Port, 0). + +wait_for_completion(Port, N) when N < 2 -> + receive + {Port, {data, Bytes}} -> + %% Relay output + io:format("~s", [Bytes]), + wait_for_completion(Port, N); + {Port, {exit_status, 0}} -> + wait_for_completion(Port, N + 1); + {Port, {exit_status, Status}} -> + {error, Status}; + {Port, eof} -> + wait_for_completion(Port, N + 1); + {'EXIT', Port, Reason} -> + io:format("Port exited with reason: ~w~n", [Reason]), + wait_for_completion(Port, N); + {'EXIT', From, Reason} -> + io:format("Got unexpected exit: ~p~n", [{'EXIT', From, Reason}]), + wait_for_completion(Port, N) + after ?PORT_TIMEOUT -> + {error, timeout} + end; +wait_for_completion(_, _) -> + ok. + + + diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/Makefile.src b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/Makefile.src new file mode 100644 index 0000000000..62672e0b95 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/Makefile.src @@ -0,0 +1,146 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# Makefile.src for c_client_erl_server test +# Note: This file *must* work for both Unix and Windows +# +# We use both `rm' (Unix) and `del' (Windows) for removing files, but +# with a `-' in front so that the error in not finding `rm' (`del') on +# Windows (Unix) is ignored. +# +# VxWorks? XXX +# + +.SUFFIXES: +.SUFFIXES: .c .h .erl .idl @obj@ .@EMULATOR@ + + +# Variables from ts: +# + +ERL_INCLUDE = @erl_include@ + +IC_INCLUDE_PATH = @ic_include_path@ +IC_LIB = @ic_libpath@@DS@@ic_lib@ + +ERL_INTERFACE_INCLUDE = @erl_interface_include@ +ERL_INTERFACE_LIB = @erl_interface_libpath@@DS@@erl_interface_lib@ +ERL_INTERFACE_EILIB = @erl_interface_libpath@@DS@@erl_interface_eilib@ +ERL_INTERFACE_THREADLIB = @erl_interface_threadlib@ +ERL_INTERFACE_SOCK_LIBS = @erl_interface_sock_libs@ + +CC = @CC@ +## XXX Should set warning flag with a DEBUG_FLAG +CFLAGS = @CFLAGS@ @DEFS@ -I@erl_include@ \ + -I@ic_include_path@ -I@erl_interface_include@ + +LD = @LD@ +LDFLAGS = @CROSSLDFLAGS@ +LIBS = $(IC_LIB) $(ERL_INTERFACE_LIB) $(ERL_INTERFACE_EILIB) \ + $(ERL_INTERFACE_THREADLIB) @LIBS@ $(ERL_INTERFACE_SOCK_LIBS) +ERLC = erlc + +# Generated C header files +GEN_H_FILES = \ + m.h \ + m_i.h \ + oe_c_erl_test.h + +# Generated C files +GEN_C_FILES = \ + m.c \ + m_i.c \ + oe_c_erl_test.c \ + oe_code_m_a.c \ + oe_code_m_arr1.c \ + oe_code_m_arr2.c \ + oe_code_m_arr3.c \ + oe_code_m_aseq.c \ + oe_code_m_b.c \ + oe_code_m_bseq.c \ + oe_code_m_dd.c \ + oe_code_m_dyn.c \ + oe_code_m_dyn_sl.c \ + oe_code_m_es.c \ + oe_code_m_et.c \ + oe_code_m_etseq.c \ + oe_code_m_fruit.c \ + oe_code_m_lseq.c \ + oe_code_m_s.c \ + oe_code_m_s_sl.c \ + oe_code_m_sarr3.c \ + oe_code_m_simple.c \ + oe_code_m_ssarr3.c \ + oe_code_m_sseq.c \ + oe_code_m_ssstr3.c \ + oe_code_m_sstr3.c \ + oe_code_m_str1.c \ + oe_code_m_str3.c \ + oe_code_m_strRec.c \ + oe_code_m_strRec_str5.c \ + oe_code_m_strRec_str7.c + +GEN_HRL_FILES = \ + m.hrl \ + m_i.hrl \ + oe_c_erl_test.hrl + +GEN_ERL_FILES = \ + m.erl \ + m_arr2.erl \ + m_arr3.erl \ + m_i.erl \ + m_str3.erl \ + oe_c_erl_test.erl + +C_FILES = $(GEN_C_FILES) c_client.c my.c + +OBJS = $(C_FILES:.c=@obj@) + +PGMS = c_client@exe@ + +ERL_FILES = $(GEN_ERL_FILES) m_i_impl.erl + +EBINS = $(ERL_FILES:.erl=.@EMULATOR@) + + +all: $(PGMS) $(EBINS) + +clean: + -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + +$(PGMS): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +$(GEN_C_FILES) $(GEN_H_FILES): c_erl_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_client}" \ + "+{user_protocol,my}" "+{c_timeout,{5000,5000}}" c_erl_test.idl + +$(GEN_ERL_FILES) $(GEN_HRL_FILES): c_erl_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" c_erl_test.idl + +.c@obj@: + $(CC) -c -o $*@obj@ $(CFLAGS) $< + +.erl.@EMULATOR@: + $(ERLC) -I $(IC_INCLUDE_PATH) $< + diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_client.c b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_client.c new file mode 100644 index 0000000000..b2c5b0c836 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_client.c @@ -0,0 +1,1763 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2010. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/* C-client for test of IC. + * + * TODO: + * + * 1. XXX #includes for VxWorks, Windows + */ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef __WIN32__ +# include <unistd.h> +#endif + +#include <string.h> + +#ifdef __WIN32__ +# include <time.h> +# include <sys/timeb.h> +#elif defined VXWORKS +#include <time.h> +#include <sys/times.h> +#else +#include <sys/time.h> +#endif + +#include <ctype.h> + +#ifdef __WIN32__ +# include <winsock2.h> +# include <windows.h> +#else +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# include <netdb.h> +#endif + +#include "ei.h" +#include "erl_interface.h" +#include "m_i.h" + +#define HOSTNAMESZ 256 +#define NODENAMESZ 512 + +#define INBUFSZ 10 +#define OUTBUFSZ 0 + +#define MAXTRIES 5 + +#define CHECK_EXCEPTION(x) \ + if ((x)->_major != CORBA_NO_EXCEPTION) { \ + fprintf(stderr,"\n\nException: %s\n\n", \ + (char *)CORBA_exception_value((x))); \ + CORBA_exception_free((x)); \ + return -1; \ + } \ + +/* XXX Should free things here too! */ +#define RETURN_IF_OK(x) \ + if ((x)) {\ + fprintf(stdout, "ok\n");\ + return 0;\ + }\ + +#define cmp_str(x,y) (!strcmp((x),(y))) +#define cmp_wstr(x,y) (!ic_wstrcmp((x),(y))) + +typedef CORBA_Environment IC_Env; + +typedef int (*TestFunc)(IC_Env *); +typedef struct { + char *name; + TestFunc func; +} TestCase; + +static char longtext[] = +"Introduction The IC application is an IDL compiler implemented in Erlang." +" The IDL compiler generates client stubs and server skeletons." +" Several back-ends are supported, and they fall into three main groups." +" For more details on IC compiler options consult the ic(3) manual page." +" Argument passing cases 1 Caller allocates all necessary storage," +" except that which may be encapsulated and managed within the parameter itself." +" 2 The caller allocates a pointer and passes it by reference to the callee." +" The callee sets the pointer to point to a valid instance of the parameter's type." +" The caller is responsible for releasing the returned storage." +" Following completion of a request, the caller is not allowed to modify any values" +" in the returned storage. To do so the caller must first copy the returned instance" +" into a new instance, then modify the new instance. 3 The caller allocates a" +" pointer to an array slice which has all the same dimensions of the original" +" array except the first, and passes it by reference to the callee. The callee sets" +" the pointer to point to a valid instance of the array. The caller is responsible for" +" releasing the returned storage. Following completion of a request, the caller is not" +" allowed to modify any values in the returned storage. To do so the caller must first" +" copy the returned instance into a new instance, then modify the new instance." +" Generated Files Two files will be generated for each scope. One set of files will be" +" generated for each module and each interface scope. An extra set is generated for" +" those definitions at top level scope. One of the files is a header file(.h), and the" +" other file is a C source code file (.c). In addition to these files a number of C" +" source files will be generated for type encodings, they are named according to the " +"following template: oe_code_<type>.c."; +static char this_node[NODENAMESZ + 1]; +static char *progname; + +/* Test function prototypes */ + +static int void_test(IC_Env *env); +static int long_test(IC_Env *env); +static int long_long_test(IC_Env *env); +static int unsigned_short_test(IC_Env *env); +static int unsigned_long_test(IC_Env *env); +static int unsigned_long_long_test(IC_Env *env); +static int double_test(IC_Env *env); +static int char_test(IC_Env *env); +static int wchar_test(IC_Env *env); +static int octet_test(IC_Env *env); +static int bool_test(IC_Env *env); +static int struct_test(IC_Env *env); +static int struct2_test(IC_Env *env); +static int seq1_test(IC_Env *env); +static int seq2_test(IC_Env *env); +static int seq3_test(IC_Env *env); +static int seq4_test(IC_Env *env); +static int seq5_test(IC_Env *env); +static int array1_test(IC_Env *env); +static int array2_test(IC_Env *env); +static int enum_test(IC_Env *env); +static int string1_test(IC_Env *env); +static int string2_test(IC_Env *env); +static int string3_test(IC_Env *env); +static int string4_test(IC_Env *env); +static int pid_test(IC_Env *env); +static int port_test(IC_Env *env); +static int ref_test(IC_Env *env); +static int term_test(IC_Env *env); +static int typedef_test(IC_Env *env); +static int inline_sequence_test(IC_Env *env); +static int term_sequence_test(IC_Env *env); +static int term_struct_test(IC_Env *env); +static int wstring1_test(IC_Env *env); + +static TestCase test_cases[] = { + {"void_test", void_test}, + {"long_test", long_test}, + {"long_long_test", long_long_test}, + {"unsigned_short_test", unsigned_short_test}, + {"unsigned_long_test", unsigned_long_test}, + {"unsigned_long_long_test", unsigned_long_long_test}, + {"double_test", double_test}, + {"char_test", char_test}, + {"wchar_test", wchar_test}, + {"octet_test", octet_test}, + {"bool_test", bool_test}, + {"struct_test", struct_test}, + {"struct2_test", struct2_test}, + {"seq1_test", seq1_test}, + {"seq2_test", seq2_test}, + {"seq3_test", seq3_test}, + {"seq4_test", seq4_test}, + {"seq5_test", seq5_test}, + {"array1_test", array1_test}, + {"array2_test", array2_test}, + {"enum_test", enum_test}, + {"string1_test", string1_test}, + {"string2_test", string2_test}, + {"string3_test", string3_test}, + {"string4_test", string4_test}, + {"pid_test", pid_test}, + {"port_test", port_test}, + {"ref_test", ref_test}, + {"term_test", term_test}, + {"typedef_test", typedef_test}, + {"inline_sequence_test", inline_sequence_test}, + {"term_sequence_test", term_sequence_test}, + {"term_struct_test", term_struct_test}, + {"wstring1_test", wstring1_test}, + {"", NULL} +}; + +/* Other prototypes */ +static int cmp_aseq(m_aseq *a1, m_aseq *a2); +static int cmp_a(m_a *a1, m_a *a2); +static int cmp_bseq(m_bseq *b1, m_bseq *b2); +static int cmp_b(m_b *b1, m_b *b2); +static int cmp_lseq(m_lseq *b1, m_lseq *b2); +static int cmp_etseq(m_etseq *b1, m_etseq *b2); +static int cmp_et(m_et* b1, m_et *b2); +static int cmp_es(m_es *b1, m_es *b2); +static int cmp_arr1(m_arr1 b1, m_arr1 b2); +static int cmp_dd(m_dd b1, m_dd b2); +static int cmp_strRec(m_strRec *b1, m_strRec *b2); +static int cmp_sseq(m_sseq *b1, m_sseq *b2); +static int cmp_pid(erlang_pid *p1, erlang_pid *p2); +static int cmp_port(erlang_port *p1, erlang_port *p2); +static int cmp_ref(erlang_ref *p1, erlang_ref *p2); +static int cmp_s(m_s *b1, m_s *b2); +static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2); +static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2); +static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2); +static int cmp_arr3(m_arr3 b1, m_arr3 b2); + +static void print_aseq(m_aseq *a); +static void print_a(m_a *a); +static void print_bseq(m_bseq *b); +static void print_lseq(m_lseq *b); +static void print_b(m_b *b); +static void print_etseq(m_etseq *b); +static void print_et(m_et* b); +static void print_es(m_es *b); +static void print_arr1(long a[500]); +static void print_dd(long a[2][3]); +static void print_strRec(m_strRec* sr); +static void print_sseq(m_sseq *b); +static void print_pid(erlang_pid *p); +static void print_port(erlang_port *p); +static void print_ref(erlang_ref *p); +static void print_term(ETERM *t); +static void print_s(m_s *p); +static void print_ssstr3(m_ssstr3 *b1); +static void print_ssarr3(m_ssarr3 *b1); +static void print_sarr3(m_sarr3 *b1); +static void print_arr3(m_arr3 b1); +static void print_wstr(CORBA_wchar *ws); + +static void free_etseq_buf(m_etseq *b); +static void free_et(m_et* b); + +#ifdef __WIN32__ +typedef struct { + long tv_sec; + long tv_usec; +} MyTimeval; +#else +typedef struct timeval MyTimeval; +#endif +static void my_gettimeofday(MyTimeval *tv); +static void showtime(MyTimeval *start, MyTimeval *stop); +static void usage(void); +static void done(int r); + + + +/* main */ + +#ifdef VXWORKS +int client(int argc, char **argv) +#else +int main(int argc, char **argv) +#endif +{ + struct hostent *hp; + erlang_pid pid; + MyTimeval start, stop; + int i, fd, ires, tres; + IC_Env *env; + int tries = 0; + char *this_node_name = NULL; + char *peer_node = NULL; + char *peer_process_name = NULL; + char *cookie = NULL; + char host[HOSTNAMESZ + 1]; + TestFunc test_func = NULL; + TestCase *test_case; + char *test_case_name = NULL; + +#ifdef __WIN32__ + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD(2, 0); + + if (WSAStartup(wVersionRequested, &wsaData) != 0) { + fprintf(stderr, "Could not load winsock2 v2.0 compatible DLL"); + exit(1); + } +#endif + + progname = argv[0]; + host[HOSTNAMESZ] = '\0'; + if (gethostname(host, HOSTNAMESZ) < 0) { + fprintf(stderr, "Can't find own hostname\n"); + done(1); + } + if ((hp = gethostbyname(host)) == 0) { + fprintf(stderr, "Can't get ip address for host %s\n", host); + done(1); + } + for (i = 1; i < argc; i++) { + if (cmp_str(argv[i], "-help")) { + usage(); + done(0); + } else if (cmp_str(argv[i], "-this-node-name")) { + i++; + this_node_name = argv[i]; + } else if (cmp_str(argv[i], "-peer-node")) { + i++; + peer_node = argv[i]; + } else if (cmp_str(argv[i], "-peer-process-name")) { + i++; + peer_process_name = argv[i]; + } else if (cmp_str(argv[i], "-cookie")) { + i++; + cookie = argv[i]; + } else if (cmp_str(argv[i], "-test-case")) { + i++; + test_case_name = argv[i]; + } else { + fprintf(stderr, "Error : invalid argument \"%s\"\n", argv[i]); + usage(); + done(1); + } + } + + if (this_node_name == NULL || peer_node == NULL || test_case_name == NULL + || peer_process_name == NULL || cookie == NULL) { + fprintf(stderr, "Error: missing option\n"); + usage(); + done(1); + } + + test_case = test_cases; + while (test_case->func) { + if (cmp_str(test_case->name, test_case_name)) { + test_func = test_case->func; + break; + } + test_case++; + } + if (test_func == NULL) { + fprintf(stderr, "Error: illegal test case: \"%s\"\n", test_case_name); + done(1); + } + + /* Behead hostname at first dot */ + for (i=0; host[i] != '\0'; i++) { + if (host[i] == '.') { host[i] = '\0'; break; } + } + sprintf(this_node, "%s@%s", this_node_name, host); + fprintf(stderr, "c_client: this node: \"%s\"\n", this_node); + fprintf(stderr, "c_client: peer node: \"%s\"\n", peer_node); + fprintf(stderr, "c_client: test case: \"%s\"\n", test_case_name); + + fprintf(stderr, "c_client: starting\n"); + + /* initialize erl_interface */ + erl_init(NULL, 0); + + for (tries = 0; tries < MAXTRIES; tries++) { + + /* connect to erlang node */ + + ires = erl_connect_xinit(host, this_node_name, this_node, + (struct in_addr *)*hp->h_addr_list, + cookie, 0); + + fprintf(stderr, "c_client: erl_connect_xinit(): %d\n", ires); + + fd = erl_connect(peer_node); + fprintf(stderr, "c_client: erl_connect(): %d\n", fd); + + if (fd >= 0) + break; + fprintf(stderr, "c_client: cannot connect, retrying\n"); + } + if (fd < 0) { + fprintf(stderr, "c_client: cannot connect, exiting\n"); + done(1); + } + env = CORBA_Environment_alloc(INBUFSZ, OUTBUFSZ); + env->_fd = fd; + strcpy(env->_regname, peer_process_name); + env->_to_pid = NULL; + env->_from_pid = &pid; + + strcpy(pid.node, this_node); + pid.num = fd; + pid.serial = 0; + pid.creation = 0; + + my_gettimeofday(&start); + tres = test_func(env); /* Call test case */ + my_gettimeofday(&stop); + showtime(&start, &stop); + erl_close_connection(fd); + + printf("c_client: env->_inbuf before : %d\n", INBUFSZ); + printf("c_client: env->_outbuf before : %d\n", OUTBUFSZ); + printf("c_client: env->_inbuf after : %d\n", env->_inbufsz); + printf("c_client: env->_outbuf after : %d\n", env->_outbufsz); + + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + done(tres); +} + +static void usage() +{ + fprintf(stderr, "Usage: %s [-help] -this-node-name <name> " + "-peer-node <nodename> -peer-process-name <name> " + "-cookie <cookie> -test-case <test case name>\n", progname); + fprintf(stderr, "Example:\n %s -this-node-name kalle " + "-peer-node olle@home -peer-process-name idltest " + "-cookie oa678er -test-case octet_test\n", progname); +} + +static void done(int r) +{ +#ifdef __WIN32__ + WSACleanup(); +#endif + exit(r); +} + + +/* TESTS */ + +static int void_test(IC_Env *env) +{ + fprintf(stdout, "\n======== m_i_void test ======\n\n"); + m_i_void_test(NULL,env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(1); +} + +static int long_test(IC_Env *env) +{ + long l = 4711, lo, lr; + + fprintf(stdout, "\n======== m_i_long test ======\n\n"); + lr = m_i_long_test(NULL, l, &lo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(l == lo && l == lr); + if (l != lo) + fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n", l, lo); + if (l != lr) + fprintf(stdout, " result error, sent: %ld, got: %ld\n", l, lr); + return -1; +} + +static int long_long_test(IC_Env *env) +{ + CORBA_long_long ll = 4711, llo, llr; + + fprintf(stdout, "\n======== m_i_longlong test ======\n\n"); + llr = m_i_longlong_test(NULL, ll, &llo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ll == llo && ll == llr); + if (ll != llo) + fprintf(stdout, " out parameter error, sent: %ld, got: %ld\n", + ll, llo); + if (ll != llr) + fprintf(stdout, " result error, sent: %ld, got: %ld\n", ll, llr); + return -1; +} + +static int unsigned_short_test(IC_Env *env) +{ + unsigned short x, y = 2, z; + + fprintf(stdout, "\n======== m_i_ushort test ======\n\n"); + x = m_i_ushort_test(NULL, y, &z, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(y == z && y == x); + if (y != z) + fprintf(stdout, " out parameter error, sent: %d, got: %d\n", y, z); + if (y != x) + fprintf(stdout, " result error, sent: %d, got: %d\n", y, x); + return -1; +} + + +static int unsigned_long_test(IC_Env *env) +{ + unsigned long ul = 5050, ulo, ulr; + + fprintf(stdout, "\n======== m_i_ulong test ======\n\n"); + ulr = m_i_ulong_test(NULL, ul, &ulo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ul == ulo && ul == ulr); + if (ul != ulo) + fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n", + ul, ulo); + if (ul != ulr) + fprintf(stdout, " result error, sent: %lu, got: %lu\n", ul, ulr); + return -1; +} + +/* + * Note: CORBA_unsigned_long_long is in fact a plain long. + */ +static int unsigned_long_long_test(IC_Env *env) +{ + CORBA_unsigned_long_long ull = 5050, ullo, ullr; + + fprintf(stdout, "\n======== m_i_ulonglong test ======\n\n"); + ullr = m_i_ulonglong_test(NULL, ull, &ullo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ull == ullo && ull == ullr); + if (ull != ullo) + fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n", + ull, ullo); + if (ull != ullr) + fprintf(stdout, " result error, sent: %lu, got: %lu\n", + ull, ullr); + return -1; +} + +static int double_test(IC_Env *env) +{ + double d = 12.1212, db, dr; + + fprintf(stdout, "\n======== m_i_double test ======\n\n"); + dr = m_i_double_test(NULL, d, &db, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(d == db && d == dr); + if (d != db) + fprintf(stdout, " out parameter error, sent: %f, got: %f\n", d, db); + if (d != dr) + fprintf(stdout, " result error, sent: %f, got: %f\n", d, dr); + return -1; +} + +static int char_test(IC_Env *env) +{ + char c = 'g', co, cr; + + /* char test */ + fprintf(stdout, "\n======== m_i_char test ======\n\n"); + cr = m_i_char_test(NULL, c, &co, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(c == co && c == cr); + if (c !=co) + fprintf(stdout, " out parameter error, sent: %c, got: %c\n", c, co); + if (c != cr) + fprintf(stdout, " result error, sent: %c, got: %c\n", c, cr); + return -1; +} + +static int wchar_test(IC_Env *env) +{ + CORBA_wchar wc = 103, wco, wcr; + + fprintf(stdout, "\n======== m_i_wchar test ======\n\n"); + wcr = m_i_wchar_test(NULL, wc, &wco, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(wc == wco && wc == wcr); + if (wc != wco) + fprintf(stdout, " out parameter error, sent: %lu, got: %lu\n", + wc, wco); + if (wc != wcr) + fprintf(stdout, " result error, sent: %lu, got: %lu\n", + wc, wcr); + return -1; +} + +static int octet_test(IC_Env *env) +{ + char o ='r', oo, or; + + fprintf(stdout, "\n======== m_i_octet test ======\n\n"); + or = m_i_octet_test(NULL, o, &oo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(o == oo && o == or); + if (o != oo) + fprintf(stdout, " out parameter error, sent: %c, got: %c\n", o, oo); + if (o != or) + fprintf(stdout, " result error, sent: %c, got: %c\n", o, or); + return -1; +} + +static int bool_test(IC_Env *env) +{ + unsigned char i = 0, io, ir; + + fprintf(stdout, "\n======== m_i_bool test ======\n\n"); + ir = m_i_bool_test(NULL, i, &io, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(i == io && i == ir); + if (i != io) + fprintf(stdout, " out parameter error, sent: %d, got: %d\n", i, io); + if (i != ir) + fprintf(stdout, " result error, sent: %d, got: %d\n", i, ir); + return -1; +} + +static int struct_test(IC_Env *env) +{ + m_b b = {4711, 'a'}, bo, br; + + fprintf(stdout, "\n======== m_i_struct test ======\n\n"); + br = m_i_struct_test(NULL, &b, &bo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_b(&b, &bo) && cmp_b(&b, &br)); + if (!cmp_b(&b, &bo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_b(&b); + fprintf(stdout, " got:\n"); + print_b(&bo); + fprintf(stdout, "\n"); + } + if (!cmp_b(&b, &br)) { + fprintf(stdout, " result error, sent:\n"); + print_b(&b); + fprintf(stdout, " got:\n"); + print_b(&br); + fprintf(stdout, "\n"); + } + return -1; +} + +static int struct2_test(IC_Env *env) +{ + m_es esi = {m_peach, 5050}, eso, esr; + + fprintf(stdout, "\n======== m_i_struct2 test ======\n\n"); + esr = m_i_struct2_test(NULL, &esi, &eso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_es(&esi, &eso) && cmp_es(&esi, &esr)); + if (!cmp_es(&esi, &eso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_es(&esi); + fprintf(stdout, " got:\n"); + print_es(&eso); + fprintf(stdout, "\n"); + } + if (!cmp_es(&esi, &esr)) { + fprintf(stdout, " result error, sent:\n"); + print_es(&esi); + fprintf(stdout, " got:\n"); + print_es(&esr); + fprintf(stdout, "\n"); + } + return -1; +} + + +static int seq1_test(IC_Env *env) +{ + m_bseq bs, *bso, *bsr; + + m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}}; + bs._length = 3; + bs._buffer = ba; + + fprintf(stdout, "\n======== m_i_seq1 test ======\n\n"); + bsr = m_i_seq1_test(NULL, &bs, &bso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_bseq(&bs, bso) && cmp_bseq(&bs, bsr)); + if (!cmp_bseq(&bs, bso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_bseq(&bs); + fprintf(stdout, " got:\n"); + print_bseq(bso); + fprintf(stdout, "\n"); + } + if (!cmp_bseq(&bs, bsr)) { + fprintf(stdout, " result error, sent:\n"); + print_bseq(&bs); + fprintf(stdout, " got:\n"); + print_bseq(bsr); + fprintf(stdout, "\n"); + } + CORBA_free(bso); + CORBA_free(bsr); + return -1; +} + +static int seq2_test(IC_Env *env) +{ + m_b ba[3] = {{4711, 'a'}, {4712, 'b'}, {4713, 'c'}}; + m_a a; + m_a aa[2]; + m_aseq as, *aso, *asr; + + a.l = 9999; + a.y._length = 3; + a.y._buffer = ba; + a.d = 66.89898989; + + aa[0] = a; + aa[1] = a; + as._length = 2; + as._buffer = aa; + + fprintf(stdout, "\n======== m_i_seq2 test ======\n\n"); + asr = m_i_seq2_test(NULL, &as, &aso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_aseq(&as, aso) && cmp_aseq(&as, asr)); + if (!cmp_aseq(&as, aso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_aseq(&as); + fprintf(stdout, " got:\n"); + print_aseq(aso); + fprintf(stdout, "\n"); + } + if (!cmp_aseq(&as, asr)) { + fprintf(stdout, " result error, sent:\n"); + print_aseq(&as); + fprintf(stdout, " got:\n"); + print_aseq(asr); + fprintf(stdout, "\n"); + } + CORBA_free(aso); + CORBA_free(asr); + return -1; +} + +static int seq3_test(IC_Env *env) +{ + m_lseq lsi, *lso, *lsr; + long al[500]; + int i=0; + + for (i = 0; i < 500; i++) + al[i]=i; + lsi._length = 500; + lsi._buffer = al; + + fprintf(stdout, "\n======== m_i_seq3 test ======\n\n"); + lsr = m_i_seq3_test(NULL, &lsi, &lso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_lseq(&lsi, lso) && cmp_lseq(&lsi, lsr)); + if (!cmp_lseq(&lsi, lso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_lseq(&lsi); + fprintf(stdout, " got:\n"); + print_lseq(lso); + fprintf(stdout, "\n"); + } + if (!cmp_lseq(&lsi, lsr)) { + fprintf(stdout, " result error, sent:\n"); + print_lseq(&lsi); + fprintf(stdout, " got:\n"); + print_lseq(lsr); + fprintf(stdout, "\n"); + } + CORBA_free(lso); + CORBA_free(lsr); + return -1; +} + +static int seq4_test(IC_Env *env) +{ + char *stra0[3] = {"a", "long", "time"}; + char *stra1[3] = {"ago", "there", "was"}; + char *stra2[3] = {"a", "buggy", "compiler"}; + m_sstr3 str3s[3] = {{3, 3, stra0}, {3, 3, stra1}, {3, 3, stra2}}; + m_ssstr3 str3ssi = {3, 3, str3s}; + m_ssstr3 *str3sso, *str3ssr; + + fprintf(stdout, "\n======== m_i_seq4 test ======\n\n"); + str3ssr = m_i_seq4_test(NULL, &str3ssi, &str3sso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_ssstr3(&str3ssi, str3sso) && + cmp_ssstr3(&str3ssi, str3ssr)); + if (!cmp_ssstr3(&str3ssi, str3sso)){ + fprintf(stdout, " out parameter error, sent:\n"); + print_ssstr3(&str3ssi); + fprintf(stdout, " got:\n"); + print_ssstr3(str3sso); + fprintf(stdout, "\n"); + } + if (!cmp_ssstr3(&str3ssi, str3ssr)) { + fprintf(stdout, " result error, sent:\n"); + print_ssstr3(&str3ssi); + fprintf(stdout, " got:\n"); + print_ssstr3(str3ssr); + fprintf(stdout, "\n"); + } + CORBA_free(str3sso); + CORBA_free(str3ssr); + return -1; +} + +static int seq5_test(IC_Env *env) +{ + m_arr3 arr3a[3] = { + {4711, 18931947, 3}, + {4711, 18931947, 3}, + {4711, 18931947, 3}}; + m_sarr3 arr3sa[3] = {{3, 3, arr3a}, {3, 3, arr3a}, {3, 3, arr3a}}; + m_ssarr3 arr3ssi = {3, 3, arr3sa}; + m_ssarr3 *arr3sso; + m_ssarr3 *arr3ssr; + + fprintf(stdout, "\n======== m_i_seq5 test ======\n\n"); + arr3ssr = m_i_seq5_test(NULL, &arr3ssi, &arr3sso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_ssarr3(&arr3ssi, arr3sso) && + cmp_ssarr3(&arr3ssi, arr3ssr)); + if (!cmp_ssarr3(&arr3ssi, arr3sso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_ssarr3(&arr3ssi); + fprintf(stdout, " got:\n"); + print_ssarr3(arr3sso); + fprintf(stdout, "\n"); + } + if (!cmp_ssarr3(&arr3ssi, arr3ssr)) { + fprintf(stdout, " result error, sent:\n"); + print_ssarr3(&arr3ssi); + fprintf(stdout, " got:\n"); + print_ssarr3(arr3ssr); + fprintf(stdout, "\n"); + } + CORBA_free(arr3sso); + CORBA_free(arr3ssr); + return -1; +} + +static int array1_test(IC_Env *env) +{ + int i; + long al[500]; + m_arr1 alo; + m_arr1_slice* alr; + + for (i = 0; i < 500; i++) + al[i]=i; + + fprintf(stdout, "\n======== m_i_array1 test ======\n\n"); + alr = m_i_array1_test(NULL, al, alo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_arr1(al, alo) && cmp_arr1(al, alr)); + if (!cmp_arr1(al, alo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_arr1(al); + fprintf(stdout, " got:\n"); + print_arr1(alo); + fprintf(stdout, "\n"); + } + if (!cmp_arr1(al,alr)) { + fprintf(stdout, " result error, sent:\n"); + print_arr1(al); + fprintf(stdout, " got:\n"); + print_arr1(alr); + fprintf(stdout, "\n"); + } + free(alo); + free(alr); + return -1; +} + +static int array2_test(IC_Env *env) +{ + long dl[2][3] = {{11, 2, 7}, {22, 8 ,13}}; + m_dd dlo; + m_dd_slice* dlr; + + fprintf(stdout, "\n======== m_i_array2 test ======\n\n"); + dlr = m_i_array2_test(NULL, dl, dlo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_dd(dl,dlo) && cmp_dd(dl,dlr)); + if (!cmp_dd(dl,dlo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_dd(dl); + fprintf(stdout, " got:\n"); + print_dd(dlo); + fprintf(stdout, "\n"); + } + if (!cmp_dd(dl,dlr)) { + fprintf(stdout, " result error, sent:\n"); + print_dd(dl); + fprintf(stdout, " got:\n"); + print_dd(dlr); + fprintf(stdout, "\n"); + } + free(*dlr); + return -1; +} + +static int enum_test(IC_Env *env) +{ + m_fruit ei = m_banana, eo, er; + + fprintf(stdout, "\n======== m_i_enum test ======\n\n"); + er = m_i_enum_test(NULL, ei, &eo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(ei == eo && ei == er); + if (ei != eo) + fprintf(stdout, " out parameter error, sent: %d, got: %d\n", ei, eo); + if (ei != er) + fprintf(stdout, " result error, sent: %d, got: %d\n", ei, er); + return -1; +} + +static int string1_test(IC_Env *env) +{ + char* si = longtext; + char* so; + char* sr; + + fprintf(stdout, "\n======== m_i_string1 test ======\n\n"); + sr = m_i_string1_test(NULL, si, &so, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, sr)); + if (!cmp_str(si, so)) + fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so); + if (!cmp_str(si, sr)) + fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr); + CORBA_free(so); + CORBA_free(sr); + return -1; +} + +static int string2_test(IC_Env *env) +{ + char* sa[3] = {"hello", "foo", "bar"}; + m_sseq ssi = {3, 3, sa}; + m_sseq *sso, *ssr; + + fprintf(stdout, "\n======== m_i_string2 test ======\n\n"); + ssr = m_i_string2_test(NULL, &ssi, &sso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_sseq(&ssi, sso) && cmp_sseq(&ssi, sso)); + if (!cmp_sseq(&ssi, sso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_sseq(&ssi); + fprintf(stdout, "got:\n"); + print_sseq(sso); + } + if (!cmp_sseq(&ssi, ssr)) { + fprintf(stdout, " result error, sent:\n"); + print_sseq(&ssi); + fprintf(stdout, "got:\n"); + print_sseq(ssr); + } + CORBA_free(sso); + CORBA_free(ssr); + return -1; +} + +static int string3_test(IC_Env *env) +{ + char* si = longtext; + char* so; + char* sr; + + fprintf(stdout, "\n======== m_i_string3 test ======\n\n"); + sr = m_i_string3_test(NULL, si, &so, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_str(si, so) && cmp_str(si, so)); + if (!cmp_str(si, so)) + fprintf(stdout, " out parameter error, sent: %s, got: %s\n", si, so); + if (!cmp_str(si, sr)) + fprintf(stdout, " result error, sent: %s, got: %s\n", si, sr); + CORBA_free(so); + CORBA_free(sr); + return -1; +} + +static int string4_test(IC_Env *env) +{ + char as1[100] = "a string", as2[200] = "help", as3[200] = "hello there"; + m_strRec stri = { 1, /* dd */ + as1, /* str4 */ + {{'a', 'k'}, {'z', 'g'}, {'n', 'q'}}, /* str7 */ + {3, 3, "buf"}, /* str5 */ + as2, /* str6 */ + {'m', 'f', 'o'}, /* str8 */ + as3, /* str9 */ + {3, 3, "stu"} /* str10 */ + }; + m_strRec *stro, *strr; + + fprintf(stdout, "\n======== m_i_string4 test ======\n\n"); + strr = m_i_string4_test(NULL, &stri, &stro, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_strRec(&stri,stro) && cmp_strRec(&stri,strr)); + if (!cmp_strRec(&stri,stro)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_strRec(&stri); + fprintf(stdout, " got:\n"); + print_strRec(stro); + fprintf(stdout, "\n"); + } + if (!cmp_strRec(&stri,strr)) { + fprintf(stdout, " result error, sent:\n"); + print_strRec(&stri); + fprintf(stdout, " got:\n"); + print_strRec(strr); + fprintf(stdout, "\n"); + } + CORBA_free(stro); + CORBA_free(strr); + return -1; +} + + +static int pid_test(IC_Env *env) +{ + erlang_pid pid = {"", 7, 0, 0}, pido, pidr; + + strcpy(pid.node, this_node), /* this currently running node */ + fprintf(stdout, "\n======== m_i_pid test ======\n\n"); + pidr = m_i_pid_test(NULL, &pid, &pido, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_pid(&pid, &pido) && cmp_pid(&pid, &pidr)); + if (!cmp_pid(&pid, &pido)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_pid(&pid); + fprintf(stdout, "got:\n"); + print_pid(&pido); + } + if (!cmp_pid(&pid, &pidr)) { + fprintf(stdout, " result error, sent:\n"); + print_pid(&pid); + fprintf(stdout, "got:\n"); + print_pid(&pidr); + } + return -1; +} + +static int port_test(IC_Env *env) +{ + erlang_port porti = {"node", 5, 1}, porto, portr; + + fprintf(stdout, "\n======== m_i_port test ======\n\n"); + portr = m_i_port_test(NULL, &porti, &porto, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_port(&porti, &porto) && cmp_port(&porti, &portr)); + if (!cmp_port(&porti, &porto)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_port(&porti); + fprintf(stdout, "got:\n"); + print_port(&porto); + } + if (!cmp_port(&porti, &portr)) { + fprintf(stdout, " result error, sent:\n"); + print_port(&porti); + fprintf(stdout, "got:\n"); + print_port(&portr); + } + return -1; +} + +static int ref_test(IC_Env *env) +{ + erlang_ref refi = { "node1", 3, {1, 2, 3}, 1}, + refo, refr; + + fprintf(stdout, "\n======== m_i_ref test ======\n\n"); + refr = m_i_ref_test(NULL, &refi, &refo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_ref(&refi, &refo) && cmp_ref(&refi, &refr)); + if (!cmp_ref(&refi, &refo)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_ref(&refi); + fprintf(stdout, "got:\n"); + print_ref(&refo); + } + if (!cmp_ref(&refi, &refr)) { + fprintf(stdout, " result error, sent:\n"); + print_ref(&refi); + fprintf(stdout, "got:\n"); + print_ref(&refr); + } + return -1; +} + +static int term_test(IC_Env *env) +{ + ETERM *ti, *to, *tr; + + ti = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"); + + fprintf(stdout, "\n======== m_i_term test ======\n\n"); + tr = m_i_term_test(NULL, ti, &to, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(erl_match(ti, to) && erl_match(ti, tr)); + if (!erl_match(ti, to)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_term(ti); + fprintf(stdout, "got:\n"); + print_term(to); + } + if (!erl_match(ti, tr)) { + fprintf(stdout, " result error, sent:\n"); + print_term(ti); + fprintf(stdout, "got:\n"); + print_term(tr); + } + erl_free_term(ti); + erl_free_term(to); + erl_free_term(tr); + return -1; +} + +static int typedef_test(IC_Env *env) +{ + m_banan mbi, mbo; /* erlang_port */ + m_apa mai; /* ETERM* */ + m_apa mao = NULL; + long tl; + + strcpy(mbi.node,"node"); + mbi.id = 15; + mbi.creation = 1; + + fprintf(stdout, "\n======== m_i_typedef test ======\n\n"); + mai = erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"); + tl = m_i_typedef_test(NULL, mai, &mbi, &mao, &mbo, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(erl_match(mai, mao) && cmp_port(&mbi, &mbo) && tl == 4711); + if (!erl_match(mai, mao)) { + fprintf(stdout, " out parameter error (term), sent:\n"); + print_term(mai); + fprintf(stdout, "got:\n"); + print_term(mao); + } + if (!cmp_port(&mbi, &mbo)) { + fprintf(stdout, " out parameter error (port), sent:\n"); + print_port(&mbi); + fprintf(stdout, "got:\n"); + print_port(&mbo); + } + if (tl != 4711) { + fprintf(stdout, " result error, sent: 4711, got %ld\n", tl); + } + erl_free_term(mai); + erl_free_term(mao); + return -1; +} + +static int inline_sequence_test(IC_Env *env) +{ + int i; + long al[500]; + m_s isi = {4711, {500, 10, al}}, + *iso, *isr; + + for (i = 0; i < 500; i++) + al[i]=i; + fprintf(stdout, "\n======== m_i_inline_sequence test ======\n\n"); + isr = m_i_inline_sequence_test(NULL, &isi, &iso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_s(&isi, iso) && cmp_s(&isi, isr)); + if (!cmp_s(&isi, iso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_s(&isi); + fprintf(stdout, "got:\n"); + print_s(iso); + } + if (!cmp_s(&isi, isr)) { + fprintf(stdout, " result error, sent:\n"); + print_s(&isi); + fprintf(stdout, "got:\n"); + print_s(isr); + } + CORBA_free(iso); + CORBA_free(isr); + return -1; +} + +static int term_sequence_test(IC_Env *env) +{ + ETERM* et_array[4] = { + erl_format("[{apa, 1, 23}, \"string\", {1.23, 45}]"), + erl_format("[{banan, 1, 23}, \"string\", {1.23, 45}]"), + erl_format("[{apelsin, 1, 23}, \"string\", {1.23, 45}]"), + erl_format("[{mango, 1, 23}, \"string\", {1.23, 45}]")}; + m_etseq etsi = {4, 4, et_array}, *etso, *etsr; + + fprintf(stdout, "\n======== m_i_term_sequence test ======\n\n"); + etsr = m_i_term_sequence_test(NULL, &etsi, &etso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_etseq(&etsi, etso) && cmp_etseq(&etsi, etsr)); + if (!cmp_etseq(&etsi, etso)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_etseq(&etsi); + fprintf(stdout, "got:\n"); + print_etseq(etso); + } + if (!cmp_etseq(&etsi, etsr)) { + fprintf(stdout, " result error, sent:\n"); + print_etseq(&etsi); + fprintf(stdout, "got:\n"); + print_etseq(etsr); + } + free_etseq_buf(&etsi); + free_etseq_buf(etso); + free_etseq_buf(etsr); + CORBA_free(etso); + CORBA_free(etsr); + return -1; +} + +static int term_struct_test(IC_Env *env) +{ + m_et eti = { erl_format("[{hej, 1, 23}, \"string\", {1.23, 45}]"), + 121212 }; + m_et eto, etr; + + fprintf(stdout, "\n======== m_i_term_struct test ======\n\n"); + etr = m_i_term_struct_test(NULL, &eti, &eto, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_et(&eti, &eto) && cmp_et(&eti, &etr)); + if (!cmp_et(&eti, &eto)) { + fprintf(stdout, " out parameter error, sent:\n"); + print_et(&eti); + fprintf(stdout, "got:\n"); + print_et(&eto); + } + if (!cmp_et(&eti, &etr)) { + fprintf(stdout, " result error, sent:\n"); + print_et(&eti); + fprintf(stdout, "got:\n"); + print_et(&etr); + } + free_et(&eti); + free_et(&eto); + free_et(&etr); + return -1; +} + +static int wstring1_test(IC_Env *env) +{ + CORBA_wchar wsi[] = {100, 101, 102, 103, 104, 0}, *wso, *wsr; + + fprintf(stdout, "\n======== m_i_wstring1 test ======\n\n"); + wsr = m_i_wstring1_test(NULL, wsi, &wso, env); + CHECK_EXCEPTION(env); + RETURN_IF_OK(cmp_wstr(wsi, wso) && cmp_wstr(wsi, wsr)); + if (!cmp_wstr(wsi, wso)) { + fprintf(stdout, " out parameter error, sent: \n"); + print_wstr(wsi); + fprintf(stdout, "got:\n"); + print_wstr(wso); + } + if (!cmp_wstr(wsi, wsr)) { + fprintf(stdout, " result error, sent: \n"); + print_wstr(wsi); + fprintf(stdout, "got:\n"); + print_wstr(wsr); + } + CORBA_free(wso); + CORBA_free(wsr); + return -1; +} + +/* Compare functions */ +static int cmp_aseq(m_aseq *a1, m_aseq *a2) +{ + int i; + + if (a1->_length != a2->_length) + return 0; + for (i = 0; i < a1->_length; i++) + if (cmp_a(&(a1->_buffer[i]), &(a2->_buffer[i])) == 0) + return 0; + return 1; +} + +static int cmp_a(m_a *a1, m_a *a2) +{ + return a1->l == a2->l && + a1->d == a2->d && + cmp_bseq(&a1->y, &a2->y); +} + +static int cmp_bseq(m_bseq *b1, m_bseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (cmp_b(&(b1->_buffer[i]), &(b2->_buffer[i])) == 0) + return 0; + return 1; +} + +static int cmp_b(m_b *b1, m_b *b2) +{ + return b1->l == b2->l && b1->c == b2->c; +} + +static int cmp_lseq(m_lseq *b1, m_lseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (b1->_buffer[i] != b2->_buffer[i]) + return 0; + return 1; +} + +static int cmp_etseq(m_etseq *b1, m_etseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (!erl_match(b1->_buffer[i], b2->_buffer[i])) + return 0; + return 1; +} + +static int cmp_et(m_et* b1, m_et *b2) +{ + return erl_match(b1->e, b2->e) && b1->l == b2->l; +} + +static int cmp_es(m_es *b1, m_es *b2) +{ + return b1->f == b2->f && b1->l == b2->l; +} + +static int cmp_arr1(m_arr1 b1, m_arr1 b2) +{ + int i; + + for (i = 0; i < 500; i++) + if (b1[i] != b2[i]) + return 0; + return 1; +} + +static int cmp_dd(m_dd b1, m_dd b2) +{ + + int i, j; + + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + if (b1[i][j] != b2[i][j]) + return 0; + return 1; +} + + + +static int cmp_strRec(m_strRec *b1, m_strRec *b2) +{ + int i, j; + + if (b1->bb != b2->bb) + return 0; + if (!cmp_str(b1->str4,b2->str4)) + return 0; + if (b1->str5._length != b2->str5._length) + return 0; + for (j = 0; j < b1->str5._length; j++) + if (b1->str5._buffer[j] != b2->str5._buffer[j]) + return 0; + if (!cmp_str(b1->str6,b2->str6)) + return 0; + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + if (b1->str7[i][j] != b2->str7[i][j]) + return 0; + for (j = 0; j < 3; j++) + if (b1->str8[j] != b2->str8[j]) + return 0; + if (!cmp_str(b1->str9,b2->str9)) + return 0; + if (b1->str10._length != b2->str10._length) + return 0; + for (j = 0; j < b1->str10._length; j++) + if (b1->str10._buffer[j] != b2->str10._buffer[j]) + return 0; + return 1; +} + + +static int cmp_sseq(m_sseq *b1, m_sseq *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) + if (!cmp_str(b1->_buffer[i], b2->_buffer[i])) + return 0; + return 1; +} + + +static int cmp_pid(erlang_pid *p1, erlang_pid *p2) +{ + return cmp_str(p1->node,p2-> node) && + p1->num == p2->num && + p1->serial == p2->serial && + p1->creation == p2->creation; +} + +static int cmp_port(erlang_port *p1, erlang_port *p2) +{ + return cmp_str(p1->node,p2-> node) && p1->id == p2->id; +} + +static int cmp_ref(erlang_ref *p1, erlang_ref *p2) +{ + return cmp_str(p1->node, p2->node) && + p1->len == p2->len && + (p1->len < 1 || p1->n[0] == p2->n[0]) && + (p1->len < 2 || p1->n[1] == p2->n[1]) && + (p1->len < 3 || p1->n[2] == p2->n[2]); +} + +static int cmp_s(m_s *b1, m_s *b2) +{ + int i; + + if (b1->l != b2->l) + return 0; + if (b1->sl._length != b2->sl._length) + return 0; + for (i = 0; i < b1->sl._length; i++) + if (b1->sl._buffer[i] != b2->sl._buffer[i]) + return 0; + return 1; +} + + +static int cmp_ssstr3(m_ssstr3 *b1, m_ssstr3 *b2) +{ + int i,j; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) { + if (b1->_buffer[i]._length != b2->_buffer[i]._length) + return 0; + for (j = 0; j < b1->_buffer[i]._length; j++) + if (!cmp_str(b1->_buffer[i]._buffer[j], + b2->_buffer[i]._buffer[j])) + return 0; + } + return 1; +} + + + +static int cmp_ssarr3(m_ssarr3 *b1, m_ssarr3 *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) { + if (!cmp_sarr3(&b1->_buffer[i], &b2->_buffer[i])) + return 0; + } + return 1; +} + +static int cmp_sarr3(m_sarr3 *b1, m_sarr3 *b2) +{ + int i; + + if (b1->_length != b2->_length) + return 0; + for (i = 0; i < b1->_length; i++) { + if (!cmp_arr3(b1->_buffer[i], b2->_buffer[i])) + return 0; + } + return 1; +} + +static int cmp_arr3(m_arr3 b1, m_arr3 b2) +{ + int i; + + for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++) { + if (b1[i] != b2[i]) + return 0; + } + return 1; +} + +/* Print functions */ +static void print_aseq(m_aseq *a) +{ + int i; + fprintf(stdout, "\nm_aseq size: %ld --------\n", a->_length); + for (i = 0; i < a->_length; i++) + print_a(&(a->_buffer[i])); +} + +static void print_a(m_a *a) +{ + fprintf(stdout, "\nm_a --------\n l: %ld\n d:%f\n", a->l, a->d); + print_bseq(&a->y); +} + +static void print_bseq(m_bseq *b) +{ + int i; + + fprintf(stdout, "\nm_bseq size: %ld --------\n",b->_length); + for (i = 0; i < b->_length; i++) + print_b(&(b->_buffer[i])); +} + +static void print_lseq(m_lseq *b) +{ + int i; + + fprintf(stdout, "\nm_lseq size: %ld --------\n",b->_length); + for (i = 0; i < b->_length; i++) + fprintf(stdout, "[%d]: %ld\n", i, b->_buffer[i]); +} + +static void print_b(m_b *b) +{ + fprintf(stdout, "\nm_b --------\n l: %ld\n c: %c\n", b->l, b->c); +} + + +static void print_etseq(m_etseq *b) +{ + int i; + + for (i = 0; i < b->_length; i++) { + fprintf(stdout, "[%d]:\n", i); + erl_print_term(stdout, b->_buffer[i]); + } +} + + +static void print_et(m_et* b) +{ + fprintf(stdout, "\net struct --------\n"); + erl_print_term(stdout, b->e); + fprintf(stdout, "long: %ld\n", b->l); + fprintf(stdout, "\n--------\n"); +} + +static void print_es(m_es *b) +{ + fprintf(stdout, "\nm_es --------\n f: %d\n l: %ld\n", b->f, b->l); +} + + +static void print_arr1(long a[10]) +{ + int i; + + for (i = 0; i < 10; i++) + fprintf(stdout, "\n[%d]: %ld\n", i, a[i]); +} + +static void print_dd(long a[2][3]) +{ + int i, j; + + fprintf(stdout, "\nlong dd[2][3] --------\n"); + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + fprintf(stdout, "\n[%d][%d]: %ld\n", i, j, a[i][j]); +} + + +static void print_strRec(m_strRec* sr) +{ + int i, j; + + fprintf(stdout, "\nboolean bb : %d\n",sr->bb); + fprintf(stdout, "string str4 : %s\n",sr->str4); + fprintf(stdout, "str7[2][3] :\n"); + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) + fprintf(stdout, "str7[%d][%d]: %ld\n", i, j, sr->str7[i][j]); + fprintf(stdout, "str5._length : %ld\n",sr->str5._length); + for (j = 0; j < sr->str5._length; j++) + fprintf(stdout, "str5._buffer[%d]: %c\n", j, sr->str5._buffer[j]); + fprintf(stdout, "string str6 : %s\n",sr->str6); + fprintf(stdout, "str8 :\n"); + for (j = 0; j < 3; j++) + fprintf(stdout, "str8[%d]: %c\n", j, sr->str8[j]); + fprintf(stdout, "string str9 : %s\n",sr->str9); + fprintf(stdout, "str10._length : %ld\n",sr->str10._length); + for (j = 0; j < sr->str10._length; j++) + fprintf(stdout, "str10._buffer[%d]: %c\n", j, sr->str10._buffer[j]); +} + +static void print_sseq(m_sseq *b) +{ + int i; + + fprintf(stdout, "\nm_sseq size: %ld --------\n",b->_length); + for (i = 0; i < b->_length; i++) + fprintf(stdout, "%s\n", b->_buffer[i]); + +} + + +static void print_pid(erlang_pid *p) +{ + fprintf(stdout, "\nerlang_pid --------\n node: %s\n num: %d\n " + "serial: %d\n creation: %d\n", + p->node, p->num, p->serial, p->creation); +} + +static void print_port(erlang_port *p) +{ + fprintf(stdout, "\nerlang_port --------\n node: %s\n id: %d\n " + "creation: %d\n", p->node, p->id, p->creation); +} + +static void print_ref(erlang_ref *p) +{ + fprintf(stdout, "\nerlang_ref --------\n node: %s\n len: %d\n " + "n[0]: %d\n n[1]: %d\n n[2]: %d\n creation: %d\n", + p->node, p->len, p->n[0], p->n[1], p->n[2], p->creation); +} + +static void print_term(ETERM *t) +{ + fprintf(stdout, "\nETERM --------\n"); + erl_print_term(stdout, t); + fprintf(stdout, "\n--------\n"); +} + +static void print_s(m_s *p) +{ + int i; + + fprintf(stdout, "\n%ld\n", p->l); + for (i = 0; i < p->sl._length; i++) + fprintf(stdout, "\n[%d]: %ld\n", i, p->sl._buffer[i]); +} + + +static void print_ssstr3(m_ssstr3 *b1) +{ + int i,j; + + fprintf(stdout, "\nSSSTR3 --------\n"); + fprintf(stdout,"b1->_length = %ld\n",b1->_length); + for (i = 0; i < b1->_length; i++) { + fprintf(stdout,"\nb1->_buffer[%d]._length %ld\n", + i, b1->_buffer[i]._length); + for (j = 0; j < b1->_buffer[i]._length; j++) + fprintf(stdout,"b1->_buffer[%d]._buffer[%d] = %s\n", + i, j, b1->_buffer[i]._buffer[j]); + } + fprintf(stdout, "\n--------\n"); +} + +static void print_wstr(CORBA_wchar *ws) +{ + int i = 0; + + fprintf(stdout, "\nwstr --------\n"); + while (ws[i]) { + fprintf(stdout, "[%d]: %ld\n", i, ws[i]); + i++; + } + fprintf(stdout, "\n--------\n"); +} + + +static void print_ssarr3(m_ssarr3 *b1) +{ + int i; + + fprintf(stdout, "\nssarr3 --------\n"); + fprintf(stdout,"length: %ld\n",b1->_length); + fprintf(stdout, "buffer:\n"); + for (i = 0; i < b1->_length; i++) + print_sarr3(&b1->_buffer[i]); + fprintf(stdout, "\n--------\n"); +} + +static void print_sarr3(m_sarr3 *b1) +{ + int i; + + fprintf(stdout, "\nsarr3 --------\n"); + fprintf(stdout,"length: %ld\n",b1->_length); + fprintf(stdout, "buffer:\n"); + for (i = 0; i < b1->_length; i++) + print_arr3(b1->_buffer[i]); + fprintf(stdout, "\n--------\n"); +} + +static void print_arr3(m_arr3 b1) +{ + int i; + + fprintf(stdout, "\narr3 --------\n"); + for (i = 0; i < sizeof(m_arr3)/sizeof(CORBA_long); i++) + fprintf(stdout, "%ld ", b1[i]); + fprintf(stdout, "\n--------\n"); +} + +static void free_etseq_buf(m_etseq *b) +{ + int i; + + for (i = 0; i < b->_length; i++) + erl_free_term(b->_buffer[i]); +} + +static void free_et(m_et* b) +{ + erl_free_term(b->e); +} + +static void showtime(MyTimeval *start, MyTimeval *stop) +{ + MyTimeval elapsed; + + elapsed.tv_sec = stop->tv_sec - start->tv_sec; + elapsed.tv_usec = stop->tv_usec - start->tv_usec; + while (elapsed.tv_usec < 0) { + elapsed.tv_sec -= 1; + elapsed.tv_usec += 1000000; + } + fprintf(stderr,"%ld.%06ld seconds\n",elapsed.tv_sec, elapsed.tv_usec); +} + +static void my_gettimeofday(MyTimeval *tv) +#ifdef __WIN32__ +#define EPOCH_JULIAN_DIFF 11644473600i64 +{ + SYSTEMTIME t; + FILETIME ft; + LONGLONG lft; + + GetSystemTime(&t); + SystemTimeToFileTime(&t, &ft); + memcpy(&lft, &ft, sizeof(lft)); + tv->tv_usec = (long) ((lft / 10i64) % 1000000i64); + tv->tv_sec = (long) ((lft / 10000000i64) - EPOCH_JULIAN_DIFF); +} +#elif defined VXWORKS +{ + int rate = sysClkRateGet(); /* Ticks per second */ + unsigned long ctick = tickGet(); + tv->tv_sec = ctick / rate; /* secs since reboot */ + tv->tv_usec = ((ctick - (tv->tv_sec * rate))*1000000)/rate; +} +#else +{ + gettimeofday(tv, NULL); +} +#endif diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_erl_test.idl b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_erl_test.idl new file mode 100644 index 0000000000..e687cec114 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/c_erl_test.idl @@ -0,0 +1,173 @@ + +// %CopyrightBegin% +// +// Copyright Ericsson AB 2004-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +#include "erlang.idl" + + +const short TestConst = 1; + +module m { + + const short TestConst = 2; + + struct b { + long l; + char c; + }; + + struct simple { + long l; + b b_t; + }; + + enum fruit {orange, banana, apple, peach, pear}; + + typedef sequence<long> lseq; + + typedef sequence<b> bseq; + + struct a { + long l; + bseq y; + double d; + }; + + typedef sequence<a> aseq; + + typedef sequence<string> sseq; + typedef string str; + typedef long myLong; + + typedef long arr1[500], dd[2][3]; + + typedef erlang::term apa; + typedef erlang::port banan; + + typedef sequence<erlang::term> etseq; + + struct s { + long l; + sequence<long> sl; + }; + + struct es { + fruit f; + myLong l; + }; + + struct et { + erlang::term e; + long l; + }; + + + typedef sequence<char> str1; + typedef string<12> str2; + typedef char str3[3]; + + typedef sequence<string> sstr3; // sequence of string + typedef sequence<sstr3> ssstr3; // sequence of sequences of strings + + typedef long arr3[3]; // array of long + typedef sequence<arr3> sarr3; // sequence of array + typedef sequence<sarr3> ssarr3; // sequence of sequnces of arrays of strings + + struct strRec{ + boolean bb; + string str4; + long str7[3][2]; + sequence<char> str5; + string<12> str6; + str3 str8; + str2 str9; + str1 str10; + }; + + + struct dyn { + long l; + sequence<long> sl; + }; + typedef dyn arr2[1][2]; + + + interface i { + + const short TestConst = 3; + + //arr2 suck(in arr2 x, out arr2 y ); + + ///////////////////////////////// attribute long l; + + // simple types + void void_test(); + long long_test(in long a, out long a1); + long long longlong_test(in long long a, out long long a1); + unsigned short ushort_test(in unsigned short a, out unsigned short a1); + unsigned long ulong_test(in unsigned long a, out unsigned long a1); + unsigned long long ulonglong_test(in unsigned long long a, out unsigned long long a1); + double double_test(in double a, out double a1); + char char_test(in char a, out char a1); + wchar wchar_test(in wchar a, out wchar a1); + octet octet_test(in octet a, out octet a1); + boolean bool_test(in boolean a, out boolean a1); + + // Seq. and struct tests + b struct_test(in b a, out b a1); + es struct2_test(in es a, out es a1); + //simple struct3_test(in simple x, out simple y); + bseq seq1_test(in bseq a, out bseq a1); + aseq seq2_test(in aseq a, out aseq a1); + lseq seq3_test(in lseq a, out lseq a1); + ssstr3 seq4_test(in ssstr3 a, out ssstr3 a1); + ssarr3 seq5_test(in ssarr3 a, out ssarr3 a1); + + // Array tests + arr1 array1_test(in arr1 a, out arr1 a1); + dd array2_test(in dd a, out dd a1); + + // enum test + fruit enum_test(in fruit a, out fruit a1); + + // string tests + string string1_test(in string a, out string a1); + wstring wstring1_test(in wstring a, out wstring a1); + sseq string2_test(in sseq a, out sseq a1); + str string3_test(in str a, out str a1); + strRec string4_test(in strRec a, out strRec a1); + + // Special erlang types + erlang::pid pid_test(in erlang::pid a, out erlang::pid a1); + erlang::port port_test(in erlang::port a, out erlang::port a1); + erlang::ref ref_test(in erlang::ref a, out erlang::ref a1); + erlang::term term_test(in erlang::term a, out erlang::term a1); + + // typedef test + long typedef_test(in apa a, in banan b, out apa a1, out banan b1); + + // inlined seq. test + s inline_sequence_test(in s a, out s a1); + + // term seq. test + etseq term_sequence_test(in etseq a, out etseq a1); + // term struct test + et term_struct_test(in et a, out et a1); + + }; + +}; diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/erl_server.erl b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/erl_server.erl new file mode 100644 index 0000000000..2e624ec5c0 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/erl_server.erl @@ -0,0 +1,28 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(erl_server). + +-export([run/0, stop/0]). + +run() -> + m_i:oe_create(). + +stop() -> + gen_server:cast(cidl_test, stop). diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/m_i_impl.erl b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/m_i_impl.erl new file mode 100644 index 0000000000..0c96fb9edf --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/m_i_impl.erl @@ -0,0 +1,161 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(m_i_impl). +-include("m.hrl"). + +-export([init/1, terminate/2, void_test/1, long_test/2, ushort_test/2, + longlong_test/2, ulong_test/2, ulonglong_test/2, + double_test/2, char_test/2, wchar_test/2, octet_test/2, + bool_test/2, struct_test/2, struct2_test/2, seq1_test/2, + seq2_test/2, seq3_test/2, seq4_test/2, seq5_test/2, + array1_test/2, array2_test/2, enum_test/2, string1_test/2, + string2_test/2, string3_test/2, string4_test/2, pid_test/2, + port_test/2, ref_test/2, term_test/2, typedef_test/3, + inline_sequence_test/2, '_set_l'/2, '_get_l'/1, + term_struct_test/2, term_sequence_test/2, wstring1_test/2]). + +-define(PRINTDEBUG(Case), + io:format("erl_server: case: ~p~n" + "erl_server: location: ~p~n", [Case, [?FILE, ?LINE]])). +-define(PRINTDEBUG2(Case, Msg), + io:format("erl_server: case: ~p~n" + "erl_server: Msg: ~p~n" + "erl_server: location: ~p~n", [Case, Msg, [?FILE, ?LINE]])). + +init(Env) -> + {ok, []}. + +terminate(F, R) -> + ok. + +'_get_l'(State) -> + ?PRINTDEBUG("_get_l"), + {reply, State, State}. +void_test(State) -> + ?PRINTDEBUG("void_test"), + {reply, ok, State}. + +'_set_l'(State, V) -> + ?PRINTDEBUG2("_set_l", V), + {reply, ok, V}. +ushort_test(State, V) -> + ?PRINTDEBUG2("ushort_test", V), + {reply, {V, V}, State}. +long_test(State, V) -> + ?PRINTDEBUG2("long_test", V), + {reply, {V, V}, State}. +longlong_test(State, V) -> + ?PRINTDEBUG2("longlong_test", V), + {reply, {V, V}, State}. +ulong_test(State, V) -> + ?PRINTDEBUG2("ulong_test", V), + {reply, {V, V}, State}. +ulonglong_test(State, V) -> + ?PRINTDEBUG2("ulonglong_test", V), + {reply, {V, V}, State}. +double_test(State, V) -> + ?PRINTDEBUG2("double_test", V), + {reply, {V, V}, State}. +char_test(State, V) -> + ?PRINTDEBUG2("char_test", V), + {reply, {V, V}, State}. +wchar_test(State, V) -> + ?PRINTDEBUG2("wchar_test", V), + {reply, {V, V}, State}. +octet_test(State, V) -> + ?PRINTDEBUG2("octet_test", V), + {reply, {V, V}, State}. +bool_test(State, V) -> + ?PRINTDEBUG2("bool_test", V), + {reply, {V, V}, State}. + +struct_test(State, V) -> + ?PRINTDEBUG2("struct_test", V), + {reply, {V, V}, State}. +struct2_test(State, V) -> + ?PRINTDEBUG2("struct2_test", V), + {reply, {V, V}, State}. +seq1_test(State, V) -> + ?PRINTDEBUG2("seq1_test", V), + {reply, {V, V}, State}. +seq2_test(State, V) -> + ?PRINTDEBUG2("seq2_test", V), + {reply, {V, V}, State}. +seq3_test(State, V) -> + ?PRINTDEBUG2("seq3_test", V), + {reply, {V, V}, State}. +seq4_test(State, V) -> + ?PRINTDEBUG2("seq4_test", V), + {reply, {V, V}, State}. +seq5_test(State, V) -> + ?PRINTDEBUG2("seq5_test", V), + {reply, {V, V}, State}. +array1_test(State, V) -> + ?PRINTDEBUG2("array1_test", V), + {reply, {V, V}, State}. +array2_test(State, V) -> + ?PRINTDEBUG2("array2_test", V), + {reply, {V, V}, State}. +enum_test(State, V) -> + ?PRINTDEBUG2("enum_test", V), + {reply, {V, V}, State}. +string1_test(State, V) -> + ?PRINTDEBUG2("string1_test", V), + {reply, {V, V}, State}. +string2_test(State, V) -> + ?PRINTDEBUG2("string2_test", V), + {reply, {V, V}, State}. +string3_test(State, V) -> + ?PRINTDEBUG2("string3_test", V), + {reply, {V, V}, State}. +string4_test(State, V) -> + ?PRINTDEBUG2("string4_test", V), + {reply, {V, V}, State}. +pid_test(State, V) -> + ?PRINTDEBUG2("pid_test", V), + {reply, {V, V}, State}. +port_test(State, V) -> + ?PRINTDEBUG2("port_test", binary_to_list(term_to_binary(V))), + {reply, {V, V}, State}. +ref_test(State, V) -> + ?PRINTDEBUG2("ref_test", binary_to_list(term_to_binary(V))), + {reply, {V, V}, State}. +term_test(State, V) -> + ?PRINTDEBUG2("term_test", V), + {reply, {V, V}, State}. +typedef_test(State, A, B) -> + ?PRINTDEBUG2("typedef_test", [A,B]), + {reply, {4711, A, B}, State}. +inline_sequence_test(State, V) -> + ?PRINTDEBUG2("inline_sequence_test", V), + {reply, {V, V}, State}. +term_sequence_test(State, V) -> + ?PRINTDEBUG2("term_sequence_test", V), + {reply, {V, V}, State}. +term_struct_test(State, V) -> + ?PRINTDEBUG2("term_struct_test", V), + {reply, {V, V}, State}. +wstring1_test(State, V) -> + ?PRINTDEBUG2("wstring1_test", V), + {reply, {V, V}, State}. + + + + diff --git a/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/my.c b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/my.c new file mode 100644 index 0000000000..4e0be3fec1 --- /dev/null +++ b/lib/ic/test/c_client_erl_server_proto_tmo_SUITE_data/my.c @@ -0,0 +1,51 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include "ic.h" +#include "m_i.h" + +int my_prepare_notification_encoding(CORBA_Environment *env) +{ + return oe_prepare_notification_encoding(env); +} + +int my_send_notification_tmo(CORBA_Environment *env, unsigned int send_ms) +{ + return oe_send_notification_tmo(env, send_ms); +} + +int my_prepare_request_encoding(CORBA_Environment *env) +{ + return oe_prepare_request_encoding(env); +} + +int my_send_request_and_receive_reply_tmo(CORBA_Environment *env, + unsigned int send_ms, + unsigned int recv_ms) +{ + return oe_send_request_and_receive_reply_tmo(env, send_ms, recv_ms); +} + +int my_prepare_reply_decoding(CORBA_Environment *env) +{ + return oe_prepare_reply_decoding(env); +} + + + diff --git a/lib/ic/test/erl_client_c_server_SUITE.erl b/lib/ic/test/erl_client_c_server_SUITE.erl new file mode 100644 index 0000000000..c5f5b6a218 --- /dev/null +++ b/lib/ic/test/erl_client_c_server_SUITE.erl @@ -0,0 +1,350 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +%%---------------------------------------------------------------------- +%% Purpose : Test suite for erl-client/c-server +%%---------------------------------------------------------------------- + + +-module(erl_client_c_server_SUITE). +-include("test_server.hrl"). + +-export([init_per_testcase/2, fin_per_testcase/2, all/1, void_test/1, + long_test/1, longlong_test/1, ushort_test/1, ulong_test/1, + ulonglong_test/1, double_test/1, char_test/1, wchar_test/1, + octet_test/1, bool_test/1, struct_test/1, struct2_test/1, + seq1_test/1, seq2_test/1, seq3_test/1, seq4_test/1, + seq5_test/1, array1_test/1, array2_test/1, enum_test/1, + string1_test/1, string2_test/1, string3_test/1, + string4_test/1, pid_test/1, port_test/1, ref_test/1, + term_test/1, typedef_test/1, inline_sequence_test/1, + term_sequence_test/1, term_struct_test/1, wstring1_test/1]). + +-define(DEFAULT_TIMEOUT, 20000). +-define(PORT_TIMEOUT, 15000). +-define(CALL_TIMEOUT, 5000). + +-define(C_SERVER_NODE_NAME, idl_c_server_test). + +%% Add/remove code path and watchdog before/after each test case. +%% +init_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:add_patha(DataDir), + + %% Since other test suites use the module m_i, we have + %% to make sure we are using the right m_i module. + code:purge(m_i), + code:load_file(m_i), + + WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:del_path(DataDir), + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of IC with an Erlang client and a C server. " + "The communication is via Erlang distribution."; +all(suite) -> + [void_test, long_test, longlong_test, ushort_test, + ulong_test, ulonglong_test, double_test, + char_test, wchar_test, octet_test, bool_test, struct_test, + struct2_test, seq1_test, seq2_test, seq3_test, seq4_test, + seq5_test, array1_test, array2_test, enum_test, string1_test, + string2_test, string3_test, string4_test, pid_test, port_test, + ref_test, term_test, typedef_test, inline_sequence_test, + term_sequence_test, term_struct_test, wstring1_test]. + + +array1_test(doc) -> ""; +array1_test(suite) -> []; +array1_test(Config) -> + do_test(array1_test, Config). + +array2_test(doc) -> ""; +array2_test(suite) -> []; +array2_test(Config) -> + do_test(array2_test, Config). + +bool_test(doc) -> ""; +bool_test(suite) -> []; +bool_test(Config) -> + do_test(bool_test, Config). + +char_test(doc) -> ""; +char_test(suite) -> []; +char_test(Config) -> + do_test(char_test, Config). + +double_test(doc) -> ""; +double_test(suite) -> []; +double_test(Config) -> + do_test(double_test, Config). + +enum_test(doc) -> ""; +enum_test(suite) -> []; +enum_test(Config) -> + do_test(enum_test, Config). + +inline_sequence_test(doc) -> ""; +inline_sequence_test(suite) -> []; +inline_sequence_test(Config) -> + do_test(inline_sequence_test, Config). + +longlong_test(doc) -> ""; +longlong_test(suite) -> []; +longlong_test(Config) -> + do_test(longlong_test, Config). + +long_test(doc) -> ""; +long_test(suite) -> []; +long_test(Config) -> + do_test(long_test, Config). + +octet_test(doc) -> ""; +octet_test(suite) -> []; +octet_test(Config) -> + do_test(octet_test, Config). + +pid_test(doc) -> ""; +pid_test(suite) -> []; +pid_test(Config) -> + do_test(pid_test, Config). + +port_test(doc) -> ""; +port_test(suite) -> []; +port_test(Config) -> + do_test(port_test, Config). + +ref_test(doc) -> ""; +ref_test(suite) -> []; +ref_test(Config) -> + do_test(ref_test, Config). + +seq1_test(doc) -> ""; +seq1_test(suite) -> []; +seq1_test(Config) -> + do_test(seq1_test, Config). + +seq2_test(doc) -> ""; +seq2_test(suite) -> []; +seq2_test(Config) -> + do_test(seq2_test, Config). + +seq3_test(doc) -> ""; +seq3_test(suite) -> []; +seq3_test(Config) -> + do_test(seq3_test, Config). + +seq4_test(doc) -> ""; +seq4_test(suite) -> []; +seq4_test(Config) -> + do_test(seq4_test, Config). + +seq5_test(doc) -> ""; +seq5_test(suite) -> []; +seq5_test(Config) -> + do_test(seq5_test, Config). + +string1_test(doc) -> ""; +string1_test(suite) -> []; +string1_test(Config) -> + do_test(string1_test, Config). + +string2_test(doc) -> ""; +string2_test(suite) -> []; +string2_test(Config) -> + do_test(string2_test, Config). + +string3_test(doc) -> ""; +string3_test(suite) -> []; +string3_test(Config) -> + do_test(string3_test, Config). + +string4_test(doc) -> ""; +string4_test(suite) -> []; +string4_test(Config) -> + do_test(string4_test, Config). + +struct2_test(doc) -> ""; +struct2_test(suite) -> []; +struct2_test(Config) -> + do_test(struct2_test, Config). + +struct_test(doc) -> ""; +struct_test(suite) -> []; +struct_test(Config) -> + do_test(struct_test, Config). + +term_sequence_test(doc) -> ""; +term_sequence_test(suite) -> []; +term_sequence_test(Config) -> + do_test(term_sequence_test, Config). + +term_struct_test(doc) -> ""; +term_struct_test(suite) -> []; +term_struct_test(Config) -> + do_test(term_struct_test, Config). + +term_test(doc) -> ""; +term_test(suite) -> []; +term_test(Config) -> + do_test(term_test, Config). + +typedef_test(doc) -> ""; +typedef_test(suite) -> []; +typedef_test(Config) -> + do_test(typedef_test, Config). + +ulonglong_test(doc) -> ""; +ulonglong_test(suite) -> []; +ulonglong_test(Config) -> + do_test(ulonglong_test, Config). + +ulong_test(doc) -> ""; +ulong_test(suite) -> []; +ulong_test(Config) -> + do_test(ulong_test, Config). + +ushort_test(doc) -> ""; +ushort_test(suite) -> []; +ushort_test(Config) -> + do_test(ushort_test, Config). + +void_test(doc) -> ""; +void_test(suite) -> []; +void_test(Config) -> + do_test(void_test, Config). + +wchar_test(doc) -> ""; +wchar_test(suite) -> []; +wchar_test(Config) -> + do_test(wchar_test, Config). + +wstring1_test(doc) -> ""; +wstring1_test(suite) -> []; +wstring1_test(Config) -> + do_test(wstring1_test, Config). + + +do_test(Case, Config) -> + %% Trap exits + process_flag(trap_exit, true), + Node = atom_to_list(node()), + [_NodeName, HostName] = string:tokens(Node, "@"), + DataDir = ?config(data_dir, Config), + %% io:format("~p: data directory: ~p~n", [?MODULE, DataDir]), + Cookie = atom_to_list(erlang:get_cookie()), + ServerNodeName = atom_to_list(?C_SERVER_NODE_NAME), + %% Start C-server node as a port program. We wait for the node + %% to connect to us. + Cmd = filename:join([DataDir, "c_server"]) ++ + " -this-node-name " ++ ServerNodeName ++ + " -peer-node " ++ Node ++ + " -cookie " ++ Cookie, + Port = open_port({spawn, Cmd}, [exit_status, eof, stderr_to_stdout]), + ServerNode = list_to_atom(ServerNodeName ++ "@" ++ HostName), + Res = case wait_for_hidden_node(ServerNode) of + ok -> + %% Need a port for port_test and typedef_test + put(port_test_port, Port), + R = (catch erl_client:Case(ServerNode, ?CALL_TIMEOUT)), + case wait_for_completion(Port) of + {error, timeout} -> + kill_off_node(ServerNode); + _ -> + ok + end, + R; + {error, timeout} -> + case wait_for_completion(Port) of + {error, timeout} -> + kill_off_node(ServerNode); + _ -> + ok + end, + {error, timeout} + end, + process_flag(trap_exit, false), + true = Res. + + +%% Wait for eof *and* exit status, but return if exit status indicates +%% an error, or we have been waiting more than PORT_TIMEOUT seconds. +%% +wait_for_completion(Port) -> + wait_for_completion(Port, 0). + +wait_for_completion(Port, N) when N < 2 -> + receive + {Port, {data, Bytes}} -> + %% Relay output + io:format("~s", [Bytes]), + wait_for_completion(Port, N); + {Port, {exit_status, 0}} -> + wait_for_completion(Port, N + 1); + {Port, {exit_status, Status}} -> + {error, Status}; + {Port, eof} -> + wait_for_completion(Port, N + 1); + {'EXIT', Port, Reason} -> + io:format("Port exited with reason: ~w~n", [Reason]), + wait_for_completion(Port, N); + {'EXIT', From, Reason} -> + io:format("Got unexpected exit: ~p~n", [{'EXIT', From, Reason}]), + wait_for_completion(Port, N) + after ?PORT_TIMEOUT -> + {error, timeout} + end; +wait_for_completion(_, _) -> + ok. + +wait_for_hidden_node(Node) -> + Times = ?DEFAULT_TIMEOUT div 100, + wait_for_hidden_node(Node, Times, 100). + +wait_for_hidden_node(Node, Times, WaitTime) when Times > 0 -> + io:format("Waiting for hidden node: ~p~n", [Node]), + case lists:member(Node, erlang:nodes(hidden)) of + true -> + ok; + false -> + delay(WaitTime), + wait_for_hidden_node(Node, Times - 1, WaitTime) + end; +wait_for_hidden_node(_Node, _, _WaitTime) -> + {error, timeout}. + +kill_off_node(Node) -> + catch rpc:cast(Node, erlang, halt, [1]). + +delay(Time) -> + receive + after Time -> + ok + end. + + + + diff --git a/lib/ic/test/erl_client_c_server_SUITE_data/Makefile.src b/lib/ic/test/erl_client_c_server_SUITE_data/Makefile.src new file mode 100644 index 0000000000..cd34d2b247 --- /dev/null +++ b/lib/ic/test/erl_client_c_server_SUITE_data/Makefile.src @@ -0,0 +1,150 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2002-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# Makefile.src for erl_client_c_server test +# Note: This file *must* work for both Unix and Windows +# +# We use both `rm' (Unix) and `del' (Windows) for removing files, but +# with a `-' in front so that the error in not finding `rm' (`del') on +# Windows (Unix) is ignored. +# +# VxWorks? XXX +# + +.SUFFIXES: +.SUFFIXES: .c .h .erl .idl @obj@ .@EMULATOR@ + + +# Variables from ts: +# + +ERL_INCLUDE = @erl_include@ + +IC_INCLUDE_PATH = @ic_include_path@ +IC_LIB = @ic_libpath@@DS@@ic_lib@ + +ERL_INTERFACE_INCLUDE = @erl_interface_include@ +ERL_INTERFACE_LIB = @erl_interface_libpath@@DS@@erl_interface_lib@ +ERL_INTERFACE_EILIB = @erl_interface_libpath@@DS@@erl_interface_eilib@ +ERL_INTERFACE_THREADLIB = @erl_interface_threadlib@ +ERL_INTERFACE_SOCK_LIBS = @erl_interface_sock_libs@ + +CC = @CC@ +## XXX Should set warning flag with a DEBUG_FLAG +CFLAGS = @CFLAGS@ @DEFS@ -I$(ERL_INCLUDE) \ + -I$(IC_INCLUDE_PATH) -I$(ERL_INTERFACE_INCLUDE) + +LD = @LD@ +LDFLAGS = @CROSSLDFLAGS@ +LIBS = $(IC_LIB) $(ERL_INTERFACE_LIB) $(ERL_INTERFACE_EILIB) \ + $(ERL_INTERFACE_THREADLIB) @LIBS@ $(ERL_INTERFACE_SOCK_LIBS) +ERLC = erlc + +# Generated C header files +GEN_H_FILES = \ + m__s.h \ + m_i__s.h \ + oe_erl_c_test__s.h + +# Generated C files +GEN_C_FILES = \ + m__s.c \ + m_i__s.c \ + oe_code_m_a.c \ + oe_code_m_arr1.c \ + oe_code_m_arr2.c \ + oe_code_m_arr3.c \ + oe_code_m_aseq.c \ + oe_code_m_b.c \ + oe_code_m_bseq.c \ + oe_code_m_dd.c \ + oe_code_m_dyn.c \ + oe_code_m_dyn_sl.c \ + oe_code_m_es.c \ + oe_code_m_et.c \ + oe_code_m_etseq.c \ + oe_code_m_fruit.c \ + oe_code_m_lseq.c \ + oe_code_m_s.c \ + oe_code_m_s_sl.c \ + oe_code_m_sarr3.c \ + oe_code_m_simple.c \ + oe_code_m_ssarr3.c \ + oe_code_m_sseq.c \ + oe_code_m_ssstr3.c \ + oe_code_m_sstr3.c \ + oe_code_m_str1.c \ + oe_code_m_str3.c \ + oe_code_m_strRec.c \ + oe_code_m_strRec_str5.c \ + oe_code_m_strRec_str7.c \ + oe_erl_c_test__s.c + +GEN_HRL_FILES = \ + m.hrl \ + m_i.hrl \ + oe_erl_c_test.hrl + +GEN_ERL_FILES = \ + m.erl \ + m_arr2.erl \ + m_arr3.erl \ + m_i.erl \ + m_str3.erl \ + oe_erl_c_test.erl + +C_FILES = $(GEN_C_FILES) c_server.c callbacks.c + +OBJS = $(C_FILES:.c=@obj@) + +PGMS = c_server@exe@ + +ERL_FILES = $(GEN_ERL_FILES) erl_client.erl + +EBINS = $(ERL_FILES:.erl=.@EMULATOR@) + + +all: $(PGMS) $(EBINS) + +clean: + -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + +$(PGMS): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +$(GEN_C_FILES) $(GEN_H_FILES): erl_c_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_server}" \ + "+{scoped_op_calls,true}" erl_c_test.idl + +# If we have scoped operation calls for C, we must have that for +# Erlang as well, if we use the m_i.erl file for calling the server. + +$(GEN_ERL_FILES) $(GEN_HRL_FILES): erl_c_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" \ + "+{scoped_op_calls,true}" "+{timeout,true}" erl_c_test.idl + +.c@obj@: + $(CC) -c -o $*@obj@ $(CFLAGS) $< + +.erl.@EMULATOR@: + $(ERLC) -W -I $(IC_INCLUDE_PATH) $< + diff --git a/lib/ic/test/erl_client_c_server_SUITE_data/c_server.c b/lib/ic/test/erl_client_c_server_SUITE_data/c_server.c new file mode 100644 index 0000000000..acdeff80fe --- /dev/null +++ b/lib/ic/test/erl_client_c_server_SUITE_data/c_server.c @@ -0,0 +1,299 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/* C-server for test of IC. + * + * The C-node implemented here connects to its peer node, waits for + * one message, evaluates the message, returns an result message, and + * terminates. + * + * TODO: + * + * 1. XXX #includes for VxWorks, Windows + */ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef __WIN32__ +# include <unistd.h> +#endif + +#include <string.h> + +#ifdef __WIN32__ +# include <time.h> +# include <sys/timeb.h> +#elif defined VXWORKS +# include <time.h> +# include <sys/times.h> +#else +# include <sys/time.h> +#endif + +#include <ctype.h> + +#ifdef __WIN32__ +# include <winsock2.h> +# include <windows.h> +#else +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# include <netdb.h> +#endif + +#include "ic.h" +#include "ei.h" +#include "erl_interface.h" +#include "eicode.h" +#include "m_i__s.h" +#include "m__s.h" + +#ifdef __WIN32__ +typedef struct { + long tv_sec; + long tv_usec; +} MyTimeval; +#else +typedef struct timeval MyTimeval; +#endif +static void my_gettimeofday(MyTimeval *tv); +static void showtime(MyTimeval *start, MyTimeval *stop); +static void usage(void); +static void done(int r); + +#define HOSTNAMESZ 256 +#define NODENAMESZ 512 +#define INBUFSZ 10 +#define OUTBUFSZ 0 +#define MAXTRIES 5 + +static char *progname; + +/* main */ +#ifdef VXWORKS +int c_server(int argc, char **argv) +#else +int main(int argc, char **argv) +#endif +{ + struct hostent *hp; + MyTimeval start, stop; + int i, fd, ires, tries; + CORBA_Environment *env; + char *this_node_name = NULL; + char *peer_node = NULL; + char *cookie = NULL; + char host[HOSTNAMESZ + 1]; + char this_node[NODENAMESZ + 1]; + erlang_msg msg; + int status, loop; + +#ifdef __WIN32__ + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD(2, 0); + + if (WSAStartup(wVersionRequested, &wsaData) != 0) { + fprintf(stderr, "Could not load winsock2 v2.0 compatible DLL"); + exit(1); + } +#endif + + progname = argv[0]; + host[HOSTNAMESZ] = '\0'; + if (gethostname(host, HOSTNAMESZ) < 0) { + fprintf(stderr, "Can't find own hostname\n"); + done(1); + } + if ((hp = gethostbyname(host)) == 0) { + fprintf(stderr, "Can't get ip address for host %s\n", host); + done(1); + } + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-help") == 0) { + usage(); + done(0); + } else if (strcmp(argv[i], "-this-node-name") == 0) { + i++; + this_node_name = argv[i]; + } else if (strcmp(argv[i], "-peer-node") == 0) { + i++; + peer_node = argv[i]; + } else if (strcmp(argv[i], "-cookie") == 0) { + i++; + cookie = argv[i]; + } else { + fprintf(stderr, "Error : invalid argument \"%s\"\n", argv[i]); + usage(); + done(1); + } + } + + if (this_node_name == NULL || peer_node == NULL || cookie == NULL) { + fprintf(stderr, "Error: missing option\n"); + usage(); + done(1); + } + + /* Behead hostname at first dot */ + for (i=0; host[i] != '\0'; i++) { + if (host[i] == '.') { host[i] = '\0'; break; } + } + sprintf(this_node, "%s@%s", this_node_name, host); + + fprintf(stderr, "c_server: this node: \"%s\"\n", this_node); + fprintf(stderr, "c_server: peer node: \"%s\"\n", peer_node); + + /* initialize erl_interface */ + erl_init(NULL, 0); + + for (tries = 0; tries < MAXTRIES; tries++) { + /* connect to peer node */ + ires = erl_connect_xinit(host, this_node_name, this_node, + (struct in_addr *)*hp->h_addr_list, + cookie, 0); + fprintf(stderr, "c_server: erl_connect_xinit(): %d\n", ires); + + fd = erl_connect(peer_node); + fprintf(stderr, "c_server: erl_connect(): %d\n", fd); + if (fd >= 0) + break; + fprintf(stderr, "c_server: cannot connect, retrying\n"); + } + if (fd < 0) { + fprintf(stderr, "c_server: cannot connect, exiting\n"); + done(1); + } + env = CORBA_Environment_alloc(INBUFSZ, OUTBUFSZ); + env->_fd = fd; + + status = 1; + loop = 1; + my_gettimeofday(&start); + while (status >= 0 && loop > 0) { + status = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz, + &msg, &env->_iin); + switch(status) { + case ERL_SEND: + case ERL_REG_SEND: + /* get result */ + m_i__switch(NULL, env); + switch(env->_major) { + case CORBA_NO_EXCEPTION: + break; + case CORBA_SYSTEM_EXCEPTION: + fprintf(stderr, "Request failure, reason : %s\n", + (char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + break; + default: /* Should not happen */ + CORBA_exception_free(env); + break; + } + /* send back result data */ + if (env->_iout > 0) + ei_send_encoded(env->_fd, &env->_caller, env->_outbuf, + env->_iout); + loop = 0; + break; + case ERL_TICK: + break; + default: + if (status < 0) { + fprintf(stderr, "Status negative: %d\n", status); + loop = 0; + } + break; + } + } + my_gettimeofday(&stop); + showtime(&start, &stop); + + erl_close_connection(fd); + + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + if (status < 0) + done(-status); + else + done(0); +} + +static void usage() +{ + fprintf(stderr, "Usage: %s [-help] -this-node-name <name> " + "-peer-node <nodename> -cookie <cookie>\n", progname); + fprintf(stderr, "Example:\n %s -this-node-name kalle " + "-peer-node olle@home -cookie oa678er\n", progname); +} + +static void done(int r) +{ +#ifdef __WIN32__ + WSACleanup(); +#endif + exit(r); +} + +static void showtime(MyTimeval *start, MyTimeval *stop) +{ + MyTimeval elapsed; + + elapsed.tv_sec = stop->tv_sec - start->tv_sec; + elapsed.tv_usec = stop->tv_usec - start->tv_usec; + while (elapsed.tv_usec < 0) { + elapsed.tv_sec -= 1; + elapsed.tv_usec += 1000000; + } + fprintf(stderr,"%ld.%06ld seconds\n",elapsed.tv_sec, elapsed.tv_usec); +} + + + +static void my_gettimeofday(MyTimeval *tv) +#ifdef __WIN32__ +#define EPOCH_JULIAN_DIFF 11644473600i64 +{ + SYSTEMTIME t; + FILETIME ft; + LONGLONG lft; + + GetSystemTime(&t); + SystemTimeToFileTime(&t, &ft); + memcpy(&lft, &ft, sizeof(lft)); + tv->tv_usec = (long) ((lft / 10i64) % 1000000i64); + tv->tv_sec = (long) ((lft / 10000000i64) - EPOCH_JULIAN_DIFF); +} +#elif defined VXWORKS +{ + int rate = sysClkRateGet(); /* Ticks per second */ + unsigned long ctick = tickGet(); + tv->tv_sec = ctick / rate; /* secs since reboot */ + tv->tv_usec = ((ctick - (tv->tv_sec * rate))*1000000)/rate; +} +#else +{ + gettimeofday(tv, NULL); +} +#endif diff --git a/lib/ic/test/erl_client_c_server_SUITE_data/callbacks.c b/lib/ic/test/erl_client_c_server_SUITE_data/callbacks.c new file mode 100644 index 0000000000..d6b28b619d --- /dev/null +++ b/lib/ic/test/erl_client_c_server_SUITE_data/callbacks.c @@ -0,0 +1,610 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2002-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include <stdio.h> +#include <stdlib.h> +#ifndef __WIN32__ +# include <unistd.h> +#endif +#include <string.h> +#include <ctype.h> +#include <ic.h> +#include <erl_interface.h> +#include <ei.h> +#include "m_i__s.h" + + + +/* OK */ + +void my_void_test(CORBA_Object oe_obj, + CORBA_Environment *oe_env) +{ + /* printf("void test !\n"); */ +} + +m_i_void_test__rs* m_i_void_test__cb(CORBA_Object oe_obj, + CORBA_Environment *oe_env) +{ + return (m_i_void_test__rs*) (my_void_test); +} + + + +/* OK */ + +void my_long_test(CORBA_Object oe_obj, + long* a, + long* b, + long* c, + CORBA_Environment *oe_env) +{ + /* printf("long test !\n"); */ +} + + +m_i_long_test__rs* m_i_long_test__cb(CORBA_Object oe_obj, + long* a, + long* b, + long* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_long_test__rs*) (my_long_test); +} + +/* OK */ + +void my_longlong_test(CORBA_Object oe_obj, + CORBA_long_long* a, + CORBA_long_long* b, + CORBA_long_long* c, + CORBA_Environment *oe_env) +{ + /* printf("long test !\n"); */ +} + +m_i_longlong_test__rs* m_i_longlong_test__cb(CORBA_Object oe_obj, + CORBA_long_long* a, + CORBA_long_long* b, + CORBA_long_long* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_longlong_test__rs*) (my_longlong_test); +} + +/* OK */ +void my_ulong_test(CORBA_Object oe_obj, + unsigned long* a, + unsigned long* b, + unsigned long* c, + CORBA_Environment *oe_env) +{ + /* printf("ulong test !\n"); */ +} + +m_i_ulong_test__rs* m_i_ulong_test__cb(CORBA_Object oe_obj, + unsigned long* a, + unsigned long* b, + unsigned long* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_ulong_test__rs*) (my_ulong_test); +} + +/* OK */ +void my_ulonglong_test(CORBA_Object oe_obj, + CORBA_unsigned_long_long* a, + CORBA_unsigned_long_long* b, + CORBA_unsigned_long_long* c, + CORBA_Environment *oe_env) +{ + /* printf("ulong test !\n"); */ +} + +m_i_ulonglong_test__rs* m_i_ulonglong_test__cb(CORBA_Object oe_obj, + CORBA_unsigned_long_long* a, + CORBA_unsigned_long_long* b, + CORBA_unsigned_long_long* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_ulonglong_test__rs*) (my_ulonglong_test); +} + +m_i_ushort_test__rs* m_i_ushort_test__cb(CORBA_Object oe_obj, + unsigned short* a, + unsigned short* b, + unsigned short* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_ushort_test__rs*) NULL; +} + + +/* OK */ +void my_double_test(CORBA_Object oe_obj, + double* a, + double* b, + double* c, + CORBA_Environment *oe_env) +{ + /* printf("double test !\n"); */ +} + +m_i_double_test__rs* m_i_double_test__cb(CORBA_Object oe_obj, + double* a, + double* b, + double* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_double_test__rs*) (my_double_test); +} + +/* OK */ +m_i_char_test__rs* m_i_char_test__cb(CORBA_Object oe_obj, + char* a, + char* b, + char* c, + CORBA_Environment *oe_env) +{ + m_i_char_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + + +/* OK */ +m_i_wchar_test__rs* m_i_wchar_test__cb(CORBA_Object oe_obj, + CORBA_wchar* a, + CORBA_wchar* b, + CORBA_wchar* c, + CORBA_Environment *oe_env) +{ + m_i_wchar_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +m_i_octet_test__rs* m_i_octet_test__cb(CORBA_Object oe_obj, + char* a, + char* b, + char* c, + CORBA_Environment *oe_env) +{ + m_i_octet_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +m_i_bool_test__rs* m_i_bool_test__cb(CORBA_Object oe_obj, + CORBA_boolean* a, + CORBA_boolean* b, + CORBA_boolean* c, + CORBA_Environment *oe_env) +{ + m_i_bool_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +void my_struct_test(CORBA_Object oe_obj, + m_b* a, + m_b* b, + m_b* c, + CORBA_Environment *oe_env) +{ + /* printf("struct test !\n"); */ +} + +m_i_struct_test__rs* m_i_struct_test__cb(CORBA_Object oe_obj, + m_b* a, + m_b* b, + m_b* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_struct_test__rs*) (my_struct_test); +} + +/* OK */ +m_i_struct2_test__rs* m_i_struct2_test__cb(CORBA_Object oe_obj, + m_es* a, + m_es* b, + m_es* c, + CORBA_Environment *oe_env) +{ + m_i_struct2_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +/* XXX Commented out +m_i_struct3_test__rs* m_i_struct3_test__cb(CORBA_Object oe_obj, + m_simple* a, + m_simple* b, + m_simple* c, + CORBA_Environment *oe_env) +{ + m_i_struct3_test__rs* rs = NULL; + *a = *b; + *c = *b; + return rs; +} +*/ + +/* OK */ +m_i_seq1_test__rs* m_i_seq1_test__cb(CORBA_Object oe_obj, + m_bseq** a, + m_bseq* b, + m_bseq** c, + CORBA_Environment *oe_env) +{ + m_i_seq1_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + + +/* OK */ +m_i_seq2_test__rs* m_i_seq2_test__cb(CORBA_Object oe_obj, + m_aseq** a, + m_aseq* b, + m_aseq** c, + CORBA_Environment *oe_env) +{ + m_i_seq2_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_seq3_test__rs* m_i_seq3_test__cb(CORBA_Object oe_obj, + m_lseq** a, + m_lseq* b, + m_lseq** c, + CORBA_Environment *oe_env) +{ + m_i_seq3_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_seq4_test__rs* m_i_seq4_test__cb(CORBA_Object oe_obj, + m_ssstr3** a, + m_ssstr3* b, + m_ssstr3** c, + CORBA_Environment *oe_env) +{ + m_i_seq4_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_seq5_test__rs* m_i_seq5_test__cb(CORBA_Object oe_obj, + m_ssarr3** a, + m_ssarr3* b, + m_ssarr3** c, + CORBA_Environment *oe_env) +{ + m_i_seq5_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_array1_test__rs* m_i_array1_test__cb(CORBA_Object oe_obj, + m_arr1 a, + m_arr1 b, + m_arr1 c, + CORBA_Environment *oe_env) +{ + int i; + m_i_array1_test__rs* rs = NULL; + + for (i = 0; i < 500; i++) { + a[i] = b[i]; + c[i] = b[i]; + } + return rs; +} + +/* OK */ +m_i_array2_test__rs* m_i_array2_test__cb(CORBA_Object oe_obj, + m_dd a, + m_dd b, + m_dd c, + CORBA_Environment *oe_env) +{ + int i,j; + m_i_array2_test__rs* rs = NULL; + + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) { + a[i][j] = b[i][j]; + c[i][j] = b[i][j]; + } + return rs; +} + + +/* OK */ +m_i_enum_test__rs* m_i_enum_test__cb(CORBA_Object oe_obj, + m_fruit* a, + m_fruit* b, + m_fruit* c, + CORBA_Environment *oe_env) +{ + m_i_enum_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +m_i_string1_test__rs* m_i_string1_test__cb(CORBA_Object oe_obj, + char ** a, + char * b, + char ** c, + CORBA_Environment *oe_env) +{ + m_i_string1_test__rs* rs = NULL; + + /*printf("\nString in ------> %s\n\n",b);*/ + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_string2_test__rs* m_i_string2_test__cb(CORBA_Object oe_obj, + m_sseq** a, + m_sseq* b, + m_sseq** c, + CORBA_Environment *oe_env) +{ + m_i_string2_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_string3_test__rs* m_i_string3_test__cb(CORBA_Object oe_obj, + char ** a, + char * b, + char ** c, + CORBA_Environment *oe_env) +{ + m_i_string3_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +m_i_string4_test__rs* m_i_string4_test__cb(CORBA_Object oe_obj, + m_strRec** a, + m_strRec* b, + m_strRec** c, + CORBA_Environment *oe_env) +{ + *a = b; + *c = b; + + return (m_i_string4_test__rs*) NULL; +} + +/* OK */ +m_i_wstring1_test__rs* m_i_wstring1_test__cb(CORBA_Object oe_obj, + CORBA_wchar ** a, + CORBA_wchar * b, + CORBA_wchar ** c, + CORBA_Environment *oe_env) +{ + int tmp; + m_i_wstring1_test__rs* rs = NULL; + + /*printf("\nString in ------> %s\n\n",b);*/ + + for(tmp = 0; tmp < 5; tmp++) + fprintf(stderr,"\np[%d] = %ld\n", tmp, b[tmp]); + *a = b; + *c = b; + return rs; +} + + +/* OK */ +m_i_pid_test__rs* m_i_pid_test__cb(CORBA_Object oe_obj, + erlang_pid* a, + erlang_pid* b, + erlang_pid* c, + CORBA_Environment *oe_env) +{ + m_i_pid_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +m_i_port_test__rs* m_i_port_test__cb(CORBA_Object oe_obj, + erlang_port* a, + erlang_port* b, + erlang_port* c, + CORBA_Environment *oe_env) +{ + m_i_port_test__rs* rs = NULL; + + strcpy((*a).node,(*b).node); + (*a).id = (*b).id; + (*a).creation = 0; + + strcpy((*c).node,(*b).node); + (*c).id = (*b).id; + (*c).creation = 0; + return rs; +} + +/* OK */ +m_i_ref_test__rs* m_i_ref_test__cb(CORBA_Object oe_obj, + erlang_ref* a, + erlang_ref* b, + erlang_ref* c, + CORBA_Environment *oe_env) +{ + + m_i_ref_test__rs* rs = NULL; + + strcpy((*a).node,(*b).node); + /*(*a).id = (*b).id;*/ + (*a).len = (*b).len; + (*a).n[0] = (*b).n[0]; + (*a).n[1] = (*b).n[1]; + (*a).n[2] = (*b).n[2]; + (*a).creation = 0; + + strcpy((*c).node,(*b).node); + /*(*c).id = (*b).id;*/ + (*c).len = (*b).len; + (*c).n[0] = (*b).n[0]; + (*c).n[1] = (*b).n[1]; + (*c).n[2] = (*b).n[2]; + (*c).creation = 0; + return rs; +} + +/* OK */ +m_i_term_test__rs* m_i_term_test__cb(CORBA_Object oe_obj, + ETERM** a, + ETERM** b, + ETERM** c, + CORBA_Environment *oe_env) +{ + m_i_term_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +m_i_typedef_test__rs* m_i_typedef_test__cb(CORBA_Object oe_obj, + long* a, + ETERM** b, + erlang_port* c, + ETERM** d , + erlang_port* e, + CORBA_Environment *oe_env) +{ + m_i_typedef_test__rs* rs = NULL; + + *d = *b; + strcpy((*e).node,(*c).node); + (*e).id = (*c).id; + (*e).creation = 0; + *a = 4711; + return rs; +} + +/* OK */ +m_i_inline_sequence_test__rs* m_i_inline_sequence_test__cb( + CORBA_Object oe_obj, + m_s** a, + m_s* b, + m_s** c, + CORBA_Environment *oe_env) +{ + m_i_inline_sequence_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_term_sequence_test__rs* m_i_term_sequence_test__cb( + CORBA_Object oe_obj, + m_etseq** a, + m_etseq* b, + m_etseq** c, + CORBA_Environment *oe_env) +{ + m_i_term_sequence_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + + +/* OK */ +m_i_term_struct_test__rs* m_i_term_struct_test__cb(CORBA_Object oe_obj, + m_et* a, + m_et* b, + m_et* c, + CORBA_Environment *oe_env) +{ + m_i_term_struct_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + diff --git a/lib/ic/test/erl_client_c_server_SUITE_data/erl_c_test.idl b/lib/ic/test/erl_client_c_server_SUITE_data/erl_c_test.idl new file mode 100644 index 0000000000..963bc69017 --- /dev/null +++ b/lib/ic/test/erl_client_c_server_SUITE_data/erl_c_test.idl @@ -0,0 +1,174 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 2002-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +#include "erlang.idl" + + +const short TestConst = 1; + +module m { + + const short TestConst = 2; + + struct b { + long l; + char c; + }; + + struct simple { + long l; + b b_t; + }; + + enum fruit {orange, banana, apple, peach, pear}; + + typedef sequence<long> lseq; + + typedef sequence<b> bseq; + + struct a { + long l; + bseq y; + double d; + }; + + typedef sequence<a> aseq; + + typedef sequence<string> sseq; + typedef string str; + typedef long myLong; + + typedef long arr1[500], dd[2][3]; + + typedef erlang::term apa; + typedef erlang::port banan; + + typedef sequence<erlang::term> etseq; + + struct s { + long l; + sequence<long> sl; + }; + + struct es { + fruit f; + myLong l; + }; + + struct et { + erlang::term e; + long l; + }; + + + typedef sequence<char> str1; + typedef string<12> str2; + typedef char str3[3]; + + typedef sequence<string> sstr3; // sequence of string + typedef sequence<sstr3> ssstr3; // sequence of sequences of strings + + typedef long arr3[3]; // array of long + typedef sequence<arr3> sarr3; // sequence of array + typedef sequence<sarr3> ssarr3; // sequence of sequnces of arrays of strings + + struct strRec{ + boolean bb; + string str4; + long str7[3][2]; + sequence<char> str5; + string<12> str6; + str3 str8; + str2 str9; + str1 str10; + }; + + + struct dyn { + long l; + sequence<long> sl; + }; + typedef dyn arr2[1][2]; + + + interface i { + + const short TestConst = 3; + + //arr2 suck(in arr2 x, out arr2 y ); + + ///////////////////////////////// attribute long l; + + // simple types + void void_test(); + long long_test(in long a, out long a1); + long long longlong_test(in long long a, out long long a1); + unsigned short ushort_test(in unsigned short a, out unsigned short a1); + unsigned long ulong_test(in unsigned long a, out unsigned long a1); + unsigned long long ulonglong_test(in unsigned long long a, out unsigned long long a1); + double double_test(in double a, out double a1); + char char_test(in char a, out char a1); + wchar wchar_test(in wchar a, out wchar a1); + octet octet_test(in octet a, out octet a1); + boolean bool_test(in boolean a, out boolean a1); + + // Seq. and struct tests + b struct_test(in b a, out b a1); + es struct2_test(in es a, out es a1); + //simple struct3_test(in simple x, out simple y); + bseq seq1_test(in bseq a, out bseq a1); + aseq seq2_test(in aseq a, out aseq a1); + lseq seq3_test(in lseq a, out lseq a1); + ssstr3 seq4_test(in ssstr3 a, out ssstr3 a1); + ssarr3 seq5_test(in ssarr3 a, out ssarr3 a1); + + // Array tests + arr1 array1_test(in arr1 a, out arr1 a1); + dd array2_test(in dd a, out dd a1); + + // enum test + fruit enum_test(in fruit a, out fruit a1); + + // string tests + string string1_test(in string a, out string a1); + wstring wstring1_test(in wstring a, out wstring a1); + sseq string2_test(in sseq a, out sseq a1); + str string3_test(in str a, out str a1); + strRec string4_test(in strRec a, out strRec a1); + + // Special erlang types + erlang::pid pid_test(in erlang::pid a, out erlang::pid a1); + erlang::port port_test(in erlang::port a, out erlang::port a1); + erlang::ref ref_test(in erlang::ref a, out erlang::ref a1); + erlang::term term_test(in erlang::term a, out erlang::term a1); + + // typedef test + long typedef_test(in apa a, in banan b, out apa a1, out banan b1); + + // inlined seq. test + s inline_sequence_test(in s a, out s a1); + + // term seq. test + etseq term_sequence_test(in etseq a, out etseq a1); + // term struct test + et term_struct_test(in et a, out et a1); + + }; + +}; diff --git a/lib/ic/test/erl_client_c_server_SUITE_data/erl_client.erl b/lib/ic/test/erl_client_c_server_SUITE_data/erl_client.erl new file mode 100644 index 0000000000..79ec28a921 --- /dev/null +++ b/lib/ic/test/erl_client_c_server_SUITE_data/erl_client.erl @@ -0,0 +1,331 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(erl_client). + +-export([void_test/2, long_test/2, longlong_test/2, ushort_test/2, + ulong_test/2, ulonglong_test/2, double_test/2, char_test/2, + wchar_test/2, octet_test/2, bool_test/2, struct_test/2, + struct2_test/2, seq1_test/2, seq2_test/2, seq3_test/2, + seq4_test/2, seq5_test/2, array1_test/2, array2_test/2, + enum_test/2, string1_test/2, wstring1_test/2, string2_test/2, + string3_test/2, string4_test/2, pid_test/2, port_test/2, + ref_test/2, term_test/2, typedef_test/2, + inline_sequence_test/2, term_sequence_test/2, + term_struct_test/2 + +]). + +-include("m.hrl"). +-include("m_i.hrl"). +-include("oe_erl_c_test.hrl"). + +%%b +void_test(Node, Timeout) -> + Ret = m_i:void_test({olsson, Node}, Timeout), + Ret == void. % XXX Not documented +%%e + +%%b +long_test(Node, Timeout) -> + In = max_long(), + {Ret, Out} = m_i:long_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +longlong_test(Node, Timeout) -> + In = 65537, + {Ret, Out} = m_i:longlong_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +ushort_test(Node, Timeout) -> + In = max_ushort(), + {Ret, Out} = m_i:ushort_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +ulong_test(Node, Timeout) -> + In = max_ulong(), + {Ret, Out} = m_i:ulong_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +ulonglong_test(Node, Timeout) -> + In = 65537, + {Ret, Out} = m_i:ulonglong_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +double_test(Node, Timeout) -> + In = 37768.93, + {Ret, Out} = m_i:double_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +char_test(Node, Timeout) -> + In = 80, + {Ret, Out} = m_i:char_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +wchar_test(Node, Timeout) -> + In = 4097, + {Ret, Out} = m_i:wchar_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +octet_test(Node, Timeout) -> + In = 255, + {Ret, Out} = m_i:octet_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +bool_test(Node, Timeout) -> + In = false, + {Ret, Out} = m_i:bool_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +struct_test(Node, Timeout) -> + In = #m_b{l = max_long(), c = $a}, + {Ret, Out} = m_i:struct_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +struct2_test(Node, Timeout) -> + In = #m_es{ f = banana, l = max_long()}, + {Ret, Out} = m_i:struct2_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +seq1_test(Node, Timeout) -> + B1 = #m_b{l = max_long(), c = $a}, + B2 = #m_b{l = min_long(), c = $b}, + In = [B1, B2], + {Ret, Out} = m_i:seq1_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +seq2_test(Node, Timeout) -> + B = #m_b{l = max_long(), c = $a}, + A = #m_a{l = min_long(), y = [B, B], d = 4711.31}, + In = [A, A, A], + {Ret, Out} = m_i:seq2_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +seq3_test(Node, Timeout) -> + In = [max_long(), min_long(), max_long()], + {Ret, Out} = m_i:seq3_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +seq4_test(Node, Timeout) -> + In = [["hello", "all"], ["Erlang", "users", "!"]], + {Ret, Out} = m_i:seq4_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +seq5_test(Node, Timeout) -> + Arr3 = mk_array(3, max_long()), + In = [[Arr3, Arr3], [Arr3, Arr3, Arr3]], + {Ret, Out} = m_i:seq5_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +array1_test(Node, Timeout) -> + In = mk_array(500, min_long()), + {Ret, Out} = m_i:array1_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +array2_test(Node, Timeout) -> + In = mk_array(2, mk_array(3, min_long())), + {Ret, Out} = m_i:array2_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +enum_test(Node, Timeout) -> + In = banana, + {Ret, Out} = m_i:enum_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +string1_test(Node, Timeout) -> + In = "Developing Erlang applications is fun!", + {Ret, Out} = m_i:string1_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +wstring1_test(Node, Timeout) -> + In = [1047| "eveloping Erlang applications is fun!"], + {Ret, Out} = m_i:wstring1_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +string2_test(Node, Timeout) -> + In = ["Developing Erlang applications ", "is fun!"], + {Ret, Out} = m_i:string2_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +string3_test(Node, Timeout) -> + In = "Developing Erlang applications is fun!", + {Ret, Out} = m_i:string3_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +string4_test(Node, Timeout) -> + + In = #m_strRec{ + bb = true, + str4 = "Developing Erlang applications " + "is fun!", + str7 = mk_array(3, mk_array(2, max_long())), + str5 = [$a, $b, $c, $d, $e, $f], + str6 = "123456789012", + str8 = {$x, $y, $x}, + str9 = "123456789012", + str10 = [$a, $b, $c, $d, $e, $f] + }, + {Ret, Out} = m_i:string4_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +pid_test(Node, Timeout) -> + In = self(), + {Ret, Out} = m_i:pid_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +port_test(Node, Timeout) -> + In = get(port_test_port), + {Ret, Out} = m_i:port_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +ref_test(Node, Timeout) -> + In = make_ref(), + {Ret, Out} = m_i:ref_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +term_test(Node, Timeout) -> + In = {[a, b], 17, kalle}, + {Ret, Out} = m_i:term_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +typedef_test(Node, Timeout) -> + In1 = {nisse, [1, 2], olsson}, + In2 = get(port_test_port), + {Ret, Out1, Out2} = m_i:typedef_test({olsson, Node}, Timeout, In1, In2), + %% XXX Should check that Ret is an integer. + (Out1 == In1) and (Out2 == In2). +%%e + +%%b +inline_sequence_test(Node, Timeout) -> + In = #m_s{l = min_long(), sl = [max_long(), min_long()]}, + {Ret, Out} = m_i:inline_sequence_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +term_sequence_test(Node, Timeout) -> + In = lists:duplicate(17, {nisse, [1, 2], {kalle, olsson}}), + {Ret, Out} = m_i:term_sequence_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +term_struct_test(Node, Timeout) -> + In = #m_et{e = {nisse, ["abcde"], {kalle, olsson}}, l = 4711}, + {Ret, Out} = m_i:term_struct_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + + +%% Locals + +mk_array(Es) -> + list_to_tuple(Es). + +mk_array(N, E) -> + mk_array(lists:duplicate(N, E)). + +%% max_short() -> +%% power_of_two(15) - 1. +max_long() -> + power_of_two(31) - 1. +max_longlong() -> + power_of_two(63) - 1. +max_ushort() -> + power_of_two(16) - 1. +max_ulong() -> + power_of_two(32) - 1. +max_ulonglong() -> + power_of_two(64) - 1. + +%% min_short() -> +%% -power_of_two(15). +min_long() -> + -power_of_two(31). +%% min_longlong() -> +%% -power_of_two(63). +%% min_ushort() -> +%% 0. +%% min_ulong() -> +%% 0. +%% min_ulonglong() -> +%% 0. + +power_of_two(N) -> + round(math:pow(2, N)). + diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE.erl b/lib/ic/test/erl_client_c_server_proto_SUITE.erl new file mode 100644 index 0000000000..d75feb621a --- /dev/null +++ b/lib/ic/test/erl_client_c_server_proto_SUITE.erl @@ -0,0 +1,350 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +%%---------------------------------------------------------------------- +%% Purpose : Test suite for erl-client/c-server +%%---------------------------------------------------------------------- + + +-module(erl_client_c_server_proto_SUITE). +-include("test_server.hrl"). + +-export([init_per_testcase/2, fin_per_testcase/2, all/1, void_test/1, + long_test/1, longlong_test/1, ushort_test/1, ulong_test/1, + ulonglong_test/1, double_test/1, char_test/1, wchar_test/1, + octet_test/1, bool_test/1, struct_test/1, struct2_test/1, + seq1_test/1, seq2_test/1, seq3_test/1, seq4_test/1, + seq5_test/1, array1_test/1, array2_test/1, enum_test/1, + string1_test/1, string2_test/1, string3_test/1, + string4_test/1, pid_test/1, port_test/1, ref_test/1, + term_test/1, typedef_test/1, inline_sequence_test/1, + term_sequence_test/1, term_struct_test/1, wstring1_test/1]). + +-define(DEFAULT_TIMEOUT, 20000). +-define(PORT_TIMEOUT, 15000). +-define(CALL_TIMEOUT, 5000). + +-define(C_SERVER_NODE_NAME, idl_c_server_test). + +%% Add/remove code path and watchdog before/after each test case. +%% +init_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:add_patha(DataDir), + + %% Since other test suites use the module m_i, we have + %% to make sure we are using the right m_i module. + code:purge(m_i), + code:load_file(m_i), + + WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:del_path(DataDir), + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + +all(doc) -> + "Test of IC with an Erlang client and a C server. " + "The communication is via Erlang distribution."; +all(suite) -> + [void_test, long_test, longlong_test, ushort_test, + ulong_test, ulonglong_test, double_test, + char_test, wchar_test, octet_test, bool_test, struct_test, + struct2_test, seq1_test, seq2_test, seq3_test, seq4_test, + seq5_test, array1_test, array2_test, enum_test, string1_test, + string2_test, string3_test, string4_test, pid_test, port_test, + ref_test, term_test, typedef_test, inline_sequence_test, + term_sequence_test, term_struct_test, wstring1_test]. + + +array1_test(doc) -> ""; +array1_test(suite) -> []; +array1_test(Config) -> + do_test(array1_test, Config). + +array2_test(doc) -> ""; +array2_test(suite) -> []; +array2_test(Config) -> + do_test(array2_test, Config). + +bool_test(doc) -> ""; +bool_test(suite) -> []; +bool_test(Config) -> + do_test(bool_test, Config). + +char_test(doc) -> ""; +char_test(suite) -> []; +char_test(Config) -> + do_test(char_test, Config). + +double_test(doc) -> ""; +double_test(suite) -> []; +double_test(Config) -> + do_test(double_test, Config). + +enum_test(doc) -> ""; +enum_test(suite) -> []; +enum_test(Config) -> + do_test(enum_test, Config). + +inline_sequence_test(doc) -> ""; +inline_sequence_test(suite) -> []; +inline_sequence_test(Config) -> + do_test(inline_sequence_test, Config). + +longlong_test(doc) -> ""; +longlong_test(suite) -> []; +longlong_test(Config) -> + do_test(longlong_test, Config). + +long_test(doc) -> ""; +long_test(suite) -> []; +long_test(Config) -> + do_test(long_test, Config). + +octet_test(doc) -> ""; +octet_test(suite) -> []; +octet_test(Config) -> + do_test(octet_test, Config). + +pid_test(doc) -> ""; +pid_test(suite) -> []; +pid_test(Config) -> + do_test(pid_test, Config). + +port_test(doc) -> ""; +port_test(suite) -> []; +port_test(Config) -> + do_test(port_test, Config). + +ref_test(doc) -> ""; +ref_test(suite) -> []; +ref_test(Config) -> + do_test(ref_test, Config). + +seq1_test(doc) -> ""; +seq1_test(suite) -> []; +seq1_test(Config) -> + do_test(seq1_test, Config). + +seq2_test(doc) -> ""; +seq2_test(suite) -> []; +seq2_test(Config) -> + do_test(seq2_test, Config). + +seq3_test(doc) -> ""; +seq3_test(suite) -> []; +seq3_test(Config) -> + do_test(seq3_test, Config). + +seq4_test(doc) -> ""; +seq4_test(suite) -> []; +seq4_test(Config) -> + do_test(seq4_test, Config). + +seq5_test(doc) -> ""; +seq5_test(suite) -> []; +seq5_test(Config) -> + do_test(seq5_test, Config). + +string1_test(doc) -> ""; +string1_test(suite) -> []; +string1_test(Config) -> + do_test(string1_test, Config). + +string2_test(doc) -> ""; +string2_test(suite) -> []; +string2_test(Config) -> + do_test(string2_test, Config). + +string3_test(doc) -> ""; +string3_test(suite) -> []; +string3_test(Config) -> + do_test(string3_test, Config). + +string4_test(doc) -> ""; +string4_test(suite) -> []; +string4_test(Config) -> + do_test(string4_test, Config). + +struct2_test(doc) -> ""; +struct2_test(suite) -> []; +struct2_test(Config) -> + do_test(struct2_test, Config). + +struct_test(doc) -> ""; +struct_test(suite) -> []; +struct_test(Config) -> + do_test(struct_test, Config). + +term_sequence_test(doc) -> ""; +term_sequence_test(suite) -> []; +term_sequence_test(Config) -> + do_test(term_sequence_test, Config). + +term_struct_test(doc) -> ""; +term_struct_test(suite) -> []; +term_struct_test(Config) -> + do_test(term_struct_test, Config). + +term_test(doc) -> ""; +term_test(suite) -> []; +term_test(Config) -> + do_test(term_test, Config). + +typedef_test(doc) -> ""; +typedef_test(suite) -> []; +typedef_test(Config) -> + do_test(typedef_test, Config). + +ulonglong_test(doc) -> ""; +ulonglong_test(suite) -> []; +ulonglong_test(Config) -> + do_test(ulonglong_test, Config). + +ulong_test(doc) -> ""; +ulong_test(suite) -> []; +ulong_test(Config) -> + do_test(ulong_test, Config). + +ushort_test(doc) -> ""; +ushort_test(suite) -> []; +ushort_test(Config) -> + do_test(ushort_test, Config). + +void_test(doc) -> ""; +void_test(suite) -> []; +void_test(Config) -> + do_test(void_test, Config). + +wchar_test(doc) -> ""; +wchar_test(suite) -> []; +wchar_test(Config) -> + do_test(wchar_test, Config). + +wstring1_test(doc) -> ""; +wstring1_test(suite) -> []; +wstring1_test(Config) -> + do_test(wstring1_test, Config). + + +do_test(Case, Config) -> + %% Trap exits + process_flag(trap_exit, true), + Node = atom_to_list(node()), + [_NodeName, HostName] = string:tokens(Node, "@"), + DataDir = ?config(data_dir, Config), + %% io:format("~p: data directory: ~p~n", [?MODULE, DataDir]), + Cookie = atom_to_list(erlang:get_cookie()), + ServerNodeName = atom_to_list(?C_SERVER_NODE_NAME), + %% Start C-server node as a port program. We wait for the node + %% to connect to us. + Cmd = filename:join([DataDir, "c_server"]) ++ + " -this-node-name " ++ ServerNodeName ++ + " -peer-node " ++ Node ++ + " -cookie " ++ Cookie, + Port = open_port({spawn, Cmd}, [exit_status, eof, stderr_to_stdout]), + ServerNode = list_to_atom(ServerNodeName ++ "@" ++ HostName), + Res = case wait_for_hidden_node(ServerNode) of + ok -> + %% Need a port for port_test and typedef_test + put(port_test_port, Port), + R = (catch erl_client:Case(ServerNode, ?CALL_TIMEOUT)), + case wait_for_completion(Port) of + {error, timeout} -> + kill_off_node(ServerNode); + _ -> + ok + end, + R; + {error, timeout} -> + case wait_for_completion(Port) of + {error, timeout} -> + kill_off_node(ServerNode); + _ -> + ok + end, + {error, timeout} + end, + process_flag(trap_exit, false), + true = Res. + + +%% Wait for eof *and* exit status, but return if exit status indicates +%% an error, or we have been waiting more than PORT_TIMEOUT seconds. +%% +wait_for_completion(Port) -> + wait_for_completion(Port, 0). + +wait_for_completion(Port, N) when N < 2 -> + receive + {Port, {data, Bytes}} -> + %% Relay output + io:format("~s", [Bytes]), + wait_for_completion(Port, N); + {Port, {exit_status, 0}} -> + wait_for_completion(Port, N + 1); + {Port, {exit_status, Status}} -> + {error, Status}; + {Port, eof} -> + wait_for_completion(Port, N + 1); + {'EXIT', Port, Reason} -> + io:format("Port exited with reason: ~w~n", [Reason]), + wait_for_completion(Port, N); + {'EXIT', From, Reason} -> + io:format("Got unexpected exit: ~p~n", [{'EXIT', From, Reason}]), + wait_for_completion(Port, N) + after ?PORT_TIMEOUT -> + {error, timeout} + end; +wait_for_completion(_, _) -> + ok. + +wait_for_hidden_node(Node) -> + Times = ?DEFAULT_TIMEOUT div 100, + wait_for_hidden_node(Node, Times, 100). + +wait_for_hidden_node(Node, Times, WaitTime) when Times > 0 -> + io:format("Waiting for hidden node: ~p~n", [Node]), + case lists:member(Node, erlang:nodes(hidden)) of + true -> + ok; + false -> + delay(WaitTime), + wait_for_hidden_node(Node, Times - 1, WaitTime) + end; +wait_for_hidden_node(_Node, _, _WaitTime) -> + {error, timeout}. + +kill_off_node(Node) -> + catch rpc:cast(Node, erlang, halt, [1]). + +delay(Time) -> + receive + after Time -> + ok + end. + + + + diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/Makefile.src b/lib/ic/test/erl_client_c_server_proto_SUITE_data/Makefile.src new file mode 100644 index 0000000000..b7e7ee77d0 --- /dev/null +++ b/lib/ic/test/erl_client_c_server_proto_SUITE_data/Makefile.src @@ -0,0 +1,150 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# Makefile.src for erl_client_c_server test +# Note: This file *must* work for both Unix and Windows +# +# We use both `rm' (Unix) and `del' (Windows) for removing files, but +# with a `-' in front so that the error in not finding `rm' (`del') on +# Windows (Unix) is ignored. +# +# VxWorks? XXX +# + +.SUFFIXES: +.SUFFIXES: .c .h .erl .idl @obj@ .@EMULATOR@ + + +# Variables from ts: +# + +ERL_INCLUDE = @erl_include@ + +IC_INCLUDE_PATH = @ic_include_path@ +IC_LIB = @ic_libpath@@DS@@ic_lib@ + +ERL_INTERFACE_INCLUDE = @erl_interface_include@ +ERL_INTERFACE_LIB = @erl_interface_libpath@@DS@@erl_interface_lib@ +ERL_INTERFACE_EILIB = @erl_interface_libpath@@DS@@erl_interface_eilib@ +ERL_INTERFACE_THREADLIB = @erl_interface_threadlib@ +ERL_INTERFACE_SOCK_LIBS = @erl_interface_sock_libs@ + +CC = @CC@ +## XXX Should set warning flag with a DEBUG_FLAG +CFLAGS = @CFLAGS@ @DEFS@ -I$(ERL_INCLUDE) \ + -I$(IC_INCLUDE_PATH) -I$(ERL_INTERFACE_INCLUDE) + +LD = @LD@ +LDFLAGS = @CROSSLDFLAGS@ +LIBS = $(IC_LIB) $(ERL_INTERFACE_LIB) $(ERL_INTERFACE_EILIB) \ + $(ERL_INTERFACE_THREADLIB) @LIBS@ $(ERL_INTERFACE_SOCK_LIBS) +ERLC = erlc + +# Generated C header files +GEN_H_FILES = \ + m__s.h \ + m_i__s.h \ + oe_erl_c_test__s.h + +# Generated C files +GEN_C_FILES = \ + m__s.c \ + m_i__s.c \ + oe_code_m_a.c \ + oe_code_m_arr1.c \ + oe_code_m_arr2.c \ + oe_code_m_arr3.c \ + oe_code_m_aseq.c \ + oe_code_m_b.c \ + oe_code_m_bseq.c \ + oe_code_m_dd.c \ + oe_code_m_dyn.c \ + oe_code_m_dyn_sl.c \ + oe_code_m_es.c \ + oe_code_m_et.c \ + oe_code_m_etseq.c \ + oe_code_m_fruit.c \ + oe_code_m_lseq.c \ + oe_code_m_s.c \ + oe_code_m_s_sl.c \ + oe_code_m_sarr3.c \ + oe_code_m_simple.c \ + oe_code_m_ssarr3.c \ + oe_code_m_sseq.c \ + oe_code_m_ssstr3.c \ + oe_code_m_sstr3.c \ + oe_code_m_str1.c \ + oe_code_m_str3.c \ + oe_code_m_strRec.c \ + oe_code_m_strRec_str5.c \ + oe_code_m_strRec_str7.c \ + oe_erl_c_test__s.c + +GEN_HRL_FILES = \ + m.hrl \ + m_i.hrl \ + oe_erl_c_test.hrl + +GEN_ERL_FILES = \ + m.erl \ + m_arr2.erl \ + m_arr3.erl \ + m_i.erl \ + m_str3.erl \ + oe_erl_c_test.erl + +C_FILES = $(GEN_C_FILES) c_server.c callbacks.c + +OBJS = $(C_FILES:.c=@obj@) + +PGMS = c_server@exe@ + +ERL_FILES = $(GEN_ERL_FILES) erl_client.erl + +EBINS = $(ERL_FILES:.erl=.@EMULATOR@) + + +all: $(PGMS) $(EBINS) + +clean: + -rm -f $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + -del /F /Q $(OBJS) $(GEN_C_FILES) $(GEN_H_FILES) $(PGMS) \ + $(EBINS) $(GEN_ERL_FILES) $(GEN_HRL_FILES) + +$(PGMS): $(OBJS) + $(LD) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) + +$(GEN_C_FILES) $(GEN_H_FILES): erl_c_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,c_server}" \ + "+{scoped_op_calls,true}" erl_c_test.idl + +# If we have scoped operation calls for C, we must have that for +# Erlang as well, if we use the m_i.erl file for calling the server. + +$(GEN_ERL_FILES) $(GEN_HRL_FILES): erl_c_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" \ + "+{scoped_op_calls,true}" "+{timeout,true}" erl_c_test.idl + +.c@obj@: + $(CC) -c -o $*@obj@ $(CFLAGS) $< + +.erl.@EMULATOR@: + $(ERLC) -W -I $(IC_INCLUDE_PATH) $< + diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/c_server.c b/lib/ic/test/erl_client_c_server_proto_SUITE_data/c_server.c new file mode 100644 index 0000000000..329f444112 --- /dev/null +++ b/lib/ic/test/erl_client_c_server_proto_SUITE_data/c_server.c @@ -0,0 +1,299 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +/* C-server for test of IC. + * + * The C-node implemented here connects to its peer node, waits for + * one message, evaluates the message, returns an result message, and + * terminates. + * + * TODO: + * + * 1. XXX #includes for VxWorks, Windows + */ + +#include <stdio.h> +#include <stdlib.h> + +#ifndef __WIN32__ +# include <unistd.h> +#endif + +#include <string.h> + +#ifdef __WIN32__ +# include <time.h> +# include <sys/timeb.h> +#elif defined VXWORKS +# include <time.h> +# include <sys/times.h> +#else +# include <sys/time.h> +#endif + +#include <ctype.h> + +#ifdef __WIN32__ +# include <winsock2.h> +# include <windows.h> +#else +# include <sys/types.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# include <netdb.h> +#endif + +#include "ic.h" +#include "ei.h" +#include "erl_interface.h" +#include "eicode.h" +#include "m_i__s.h" +#include "m__s.h" + +#ifdef __WIN32__ +typedef struct { + long tv_sec; + long tv_usec; +} MyTimeval; +#else +typedef struct timeval MyTimeval; +#endif +static void my_gettimeofday(MyTimeval *tv); +static void showtime(MyTimeval *start, MyTimeval *stop); +static void usage(void); +static void done(int r); + +#define HOSTNAMESZ 256 +#define NODENAMESZ 512 +#define INBUFSZ 10 +#define OUTBUFSZ 0 +#define MAXTRIES 5 + +static char *progname; + +/* main */ +#ifdef VXWORKS +int c_server(int argc, char **argv) +#else +int main(int argc, char **argv) +#endif +{ + struct hostent *hp; + MyTimeval start, stop; + int i, fd, ires, tries; + CORBA_Environment *env; + char *this_node_name = NULL; + char *peer_node = NULL; + char *cookie = NULL; + char host[HOSTNAMESZ + 1]; + char this_node[NODENAMESZ + 1]; + erlang_msg msg; + int status, loop; + +#ifdef __WIN32__ + WORD wVersionRequested; + WSADATA wsaData; + + wVersionRequested = MAKEWORD(2, 0); + + if (WSAStartup(wVersionRequested, &wsaData) != 0) { + fprintf(stderr, "Could not load winsock2 v2.0 compatible DLL"); + exit(1); + } +#endif + + progname = argv[0]; + host[HOSTNAMESZ] = '\0'; + if (gethostname(host, HOSTNAMESZ) < 0) { + fprintf(stderr, "Can't find own hostname\n"); + done(1); + } + if ((hp = gethostbyname(host)) == 0) { + fprintf(stderr, "Can't get ip address for host %s\n", host); + done(1); + } + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-help") == 0) { + usage(); + done(0); + } else if (strcmp(argv[i], "-this-node-name") == 0) { + i++; + this_node_name = argv[i]; + } else if (strcmp(argv[i], "-peer-node") == 0) { + i++; + peer_node = argv[i]; + } else if (strcmp(argv[i], "-cookie") == 0) { + i++; + cookie = argv[i]; + } else { + fprintf(stderr, "Error : invalid argument \"%s\"\n", argv[i]); + usage(); + done(1); + } + } + + if (this_node_name == NULL || peer_node == NULL || cookie == NULL) { + fprintf(stderr, "Error: missing option\n"); + usage(); + done(1); + } + + /* Behead hostname at first dot */ + for (i=0; host[i] != '\0'; i++) { + if (host[i] == '.') { host[i] = '\0'; break; } + } + sprintf(this_node, "%s@%s", this_node_name, host); + + fprintf(stderr, "c_server: this node: \"%s\"\n", this_node); + fprintf(stderr, "c_server: peer node: \"%s\"\n", peer_node); + + /* initialize erl_interface */ + erl_init(NULL, 0); + + for (tries = 0; tries < MAXTRIES; tries++) { + /* connect to peer node */ + ires = erl_connect_xinit(host, this_node_name, this_node, + (struct in_addr *)*hp->h_addr_list, + cookie, 0); + fprintf(stderr, "c_server: erl_connect_xinit(): %d\n", ires); + + fd = erl_connect(peer_node); + fprintf(stderr, "c_server: erl_connect(): %d\n", fd); + if (fd >= 0) + break; + fprintf(stderr, "c_server: cannot connect, retrying\n"); + } + if (fd < 0) { + fprintf(stderr, "c_server: cannot connect, exiting\n"); + done(1); + } + env = CORBA_Environment_alloc(INBUFSZ, OUTBUFSZ); + env->_fd = fd; + + status = 1; + loop = 1; + my_gettimeofday(&start); + while (status >= 0 && loop > 0) { + status = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz, + &msg, &env->_iin); + switch(status) { + case ERL_SEND: + case ERL_REG_SEND: + /* get result */ + m_i__switch(NULL, env); + switch(env->_major) { + case CORBA_NO_EXCEPTION: + break; + case CORBA_SYSTEM_EXCEPTION: + fprintf(stderr, "Request failure, reason : %s\n", + (char *) CORBA_exception_value(env)); + CORBA_exception_free(env); + break; + default: /* Should not happen */ + CORBA_exception_free(env); + break; + } + /* send back result data */ + if (env->_iout > 0) + ei_send_encoded(env->_fd, &env->_caller, env->_outbuf, + env->_iout); + loop = 0; + break; + case ERL_TICK: + break; + default: + if (status < 0) { + fprintf(stderr, "Status negative: %d\n", status); + loop = 0; + } + break; + } + } + my_gettimeofday(&stop); + showtime(&start, &stop); + + erl_close_connection(fd); + + CORBA_free(env->_inbuf); + CORBA_free(env->_outbuf); + CORBA_free(env); + if (status < 0) + done(-status); + else + done(0); +} + +static void usage() +{ + fprintf(stderr, "Usage: %s [-help] -this-node-name <name> " + "-peer-node <nodename> -cookie <cookie>\n", progname); + fprintf(stderr, "Example:\n %s -this-node-name kalle " + "-peer-node olle@home -cookie oa678er\n", progname); +} + +static void done(int r) +{ +#ifdef __WIN32__ + WSACleanup(); +#endif + exit(r); +} + +static void showtime(MyTimeval *start, MyTimeval *stop) +{ + MyTimeval elapsed; + + elapsed.tv_sec = stop->tv_sec - start->tv_sec; + elapsed.tv_usec = stop->tv_usec - start->tv_usec; + while (elapsed.tv_usec < 0) { + elapsed.tv_sec -= 1; + elapsed.tv_usec += 1000000; + } + fprintf(stderr,"%ld.%06ld seconds\n",elapsed.tv_sec, elapsed.tv_usec); +} + + + +static void my_gettimeofday(MyTimeval *tv) +#ifdef __WIN32__ +#define EPOCH_JULIAN_DIFF 11644473600i64 +{ + SYSTEMTIME t; + FILETIME ft; + LONGLONG lft; + + GetSystemTime(&t); + SystemTimeToFileTime(&t, &ft); + memcpy(&lft, &ft, sizeof(lft)); + tv->tv_usec = (long) ((lft / 10i64) % 1000000i64); + tv->tv_sec = (long) ((lft / 10000000i64) - EPOCH_JULIAN_DIFF); +} +#elif defined VXWORKS +{ + int rate = sysClkRateGet(); /* Ticks per second */ + unsigned long ctick = tickGet(); + tv->tv_sec = ctick / rate; /* secs since reboot */ + tv->tv_usec = ((ctick - (tv->tv_sec * rate))*1000000)/rate; +} +#else +{ + gettimeofday(tv, NULL); +} +#endif diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/callbacks.c b/lib/ic/test/erl_client_c_server_proto_SUITE_data/callbacks.c new file mode 100644 index 0000000000..b029bcc63c --- /dev/null +++ b/lib/ic/test/erl_client_c_server_proto_SUITE_data/callbacks.c @@ -0,0 +1,610 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include <stdio.h> +#include <stdlib.h> +#ifndef __WIN32__ +# include <unistd.h> +#endif +#include <string.h> +#include <ctype.h> +#include <ic.h> +#include <erl_interface.h> +#include <ei.h> +#include "m_i__s.h" + + + +/* OK */ + +void my_void_test(CORBA_Object oe_obj, + CORBA_Environment *oe_env) +{ + /* printf("void test !\n"); */ +} + +m_i_void_test__rs* m_i_void_test__cb(CORBA_Object oe_obj, + CORBA_Environment *oe_env) +{ + return (m_i_void_test__rs*) (my_void_test); +} + + + +/* OK */ + +void my_long_test(CORBA_Object oe_obj, + long* a, + long* b, + long* c, + CORBA_Environment *oe_env) +{ + /* printf("long test !\n"); */ +} + + +m_i_long_test__rs* m_i_long_test__cb(CORBA_Object oe_obj, + long* a, + long* b, + long* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_long_test__rs*) (my_long_test); +} + +/* OK */ + +void my_longlong_test(CORBA_Object oe_obj, + CORBA_long_long* a, + CORBA_long_long* b, + CORBA_long_long* c, + CORBA_Environment *oe_env) +{ + /* printf("long test !\n"); */ +} + +m_i_longlong_test__rs* m_i_longlong_test__cb(CORBA_Object oe_obj, + CORBA_long_long* a, + CORBA_long_long* b, + CORBA_long_long* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_longlong_test__rs*) (my_longlong_test); +} + +/* OK */ +void my_ulong_test(CORBA_Object oe_obj, + unsigned long* a, + unsigned long* b, + unsigned long* c, + CORBA_Environment *oe_env) +{ + /* printf("ulong test !\n"); */ +} + +m_i_ulong_test__rs* m_i_ulong_test__cb(CORBA_Object oe_obj, + unsigned long* a, + unsigned long* b, + unsigned long* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_ulong_test__rs*) (my_ulong_test); +} + +/* OK */ +void my_ulonglong_test(CORBA_Object oe_obj, + CORBA_unsigned_long_long* a, + CORBA_unsigned_long_long* b, + CORBA_unsigned_long_long* c, + CORBA_Environment *oe_env) +{ + /* printf("ulong test !\n"); */ +} + +m_i_ulonglong_test__rs* m_i_ulonglong_test__cb(CORBA_Object oe_obj, + CORBA_unsigned_long_long* a, + CORBA_unsigned_long_long* b, + CORBA_unsigned_long_long* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_ulonglong_test__rs*) (my_ulonglong_test); +} + +m_i_ushort_test__rs* m_i_ushort_test__cb(CORBA_Object oe_obj, + unsigned short* a, + unsigned short* b, + unsigned short* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_ushort_test__rs*) NULL; +} + + +/* OK */ +void my_double_test(CORBA_Object oe_obj, + double* a, + double* b, + double* c, + CORBA_Environment *oe_env) +{ + /* printf("double test !\n"); */ +} + +m_i_double_test__rs* m_i_double_test__cb(CORBA_Object oe_obj, + double* a, + double* b, + double* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_double_test__rs*) (my_double_test); +} + +/* OK */ +m_i_char_test__rs* m_i_char_test__cb(CORBA_Object oe_obj, + char* a, + char* b, + char* c, + CORBA_Environment *oe_env) +{ + m_i_char_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + + +/* OK */ +m_i_wchar_test__rs* m_i_wchar_test__cb(CORBA_Object oe_obj, + CORBA_wchar* a, + CORBA_wchar* b, + CORBA_wchar* c, + CORBA_Environment *oe_env) +{ + m_i_wchar_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +m_i_octet_test__rs* m_i_octet_test__cb(CORBA_Object oe_obj, + char* a, + char* b, + char* c, + CORBA_Environment *oe_env) +{ + m_i_octet_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +m_i_bool_test__rs* m_i_bool_test__cb(CORBA_Object oe_obj, + CORBA_boolean* a, + CORBA_boolean* b, + CORBA_boolean* c, + CORBA_Environment *oe_env) +{ + m_i_bool_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +void my_struct_test(CORBA_Object oe_obj, + m_b* a, + m_b* b, + m_b* c, + CORBA_Environment *oe_env) +{ + /* printf("struct test !\n"); */ +} + +m_i_struct_test__rs* m_i_struct_test__cb(CORBA_Object oe_obj, + m_b* a, + m_b* b, + m_b* c, + CORBA_Environment *oe_env) +{ + *a = *b; + *c = *b; + return (m_i_struct_test__rs*) (my_struct_test); +} + +/* OK */ +m_i_struct2_test__rs* m_i_struct2_test__cb(CORBA_Object oe_obj, + m_es* a, + m_es* b, + m_es* c, + CORBA_Environment *oe_env) +{ + m_i_struct2_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +/* XXX Commented out +m_i_struct3_test__rs* m_i_struct3_test__cb(CORBA_Object oe_obj, + m_simple* a, + m_simple* b, + m_simple* c, + CORBA_Environment *oe_env) +{ + m_i_struct3_test__rs* rs = NULL; + *a = *b; + *c = *b; + return rs; +} +*/ + +/* OK */ +m_i_seq1_test__rs* m_i_seq1_test__cb(CORBA_Object oe_obj, + m_bseq** a, + m_bseq* b, + m_bseq** c, + CORBA_Environment *oe_env) +{ + m_i_seq1_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + + +/* OK */ +m_i_seq2_test__rs* m_i_seq2_test__cb(CORBA_Object oe_obj, + m_aseq** a, + m_aseq* b, + m_aseq** c, + CORBA_Environment *oe_env) +{ + m_i_seq2_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_seq3_test__rs* m_i_seq3_test__cb(CORBA_Object oe_obj, + m_lseq** a, + m_lseq* b, + m_lseq** c, + CORBA_Environment *oe_env) +{ + m_i_seq3_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_seq4_test__rs* m_i_seq4_test__cb(CORBA_Object oe_obj, + m_ssstr3** a, + m_ssstr3* b, + m_ssstr3** c, + CORBA_Environment *oe_env) +{ + m_i_seq4_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_seq5_test__rs* m_i_seq5_test__cb(CORBA_Object oe_obj, + m_ssarr3** a, + m_ssarr3* b, + m_ssarr3** c, + CORBA_Environment *oe_env) +{ + m_i_seq5_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_array1_test__rs* m_i_array1_test__cb(CORBA_Object oe_obj, + m_arr1 a, + m_arr1 b, + m_arr1 c, + CORBA_Environment *oe_env) +{ + int i; + m_i_array1_test__rs* rs = NULL; + + for (i = 0; i < 500; i++) { + a[i] = b[i]; + c[i] = b[i]; + } + return rs; +} + +/* OK */ +m_i_array2_test__rs* m_i_array2_test__cb(CORBA_Object oe_obj, + m_dd a, + m_dd b, + m_dd c, + CORBA_Environment *oe_env) +{ + int i,j; + m_i_array2_test__rs* rs = NULL; + + for (i = 0; i < 2; i++) + for (j = 0; j < 3; j++) { + a[i][j] = b[i][j]; + c[i][j] = b[i][j]; + } + return rs; +} + + +/* OK */ +m_i_enum_test__rs* m_i_enum_test__cb(CORBA_Object oe_obj, + m_fruit* a, + m_fruit* b, + m_fruit* c, + CORBA_Environment *oe_env) +{ + m_i_enum_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +m_i_string1_test__rs* m_i_string1_test__cb(CORBA_Object oe_obj, + char ** a, + char * b, + char ** c, + CORBA_Environment *oe_env) +{ + m_i_string1_test__rs* rs = NULL; + + /*printf("\nString in ------> %s\n\n",b);*/ + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_string2_test__rs* m_i_string2_test__cb(CORBA_Object oe_obj, + m_sseq** a, + m_sseq* b, + m_sseq** c, + CORBA_Environment *oe_env) +{ + m_i_string2_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_string3_test__rs* m_i_string3_test__cb(CORBA_Object oe_obj, + char ** a, + char * b, + char ** c, + CORBA_Environment *oe_env) +{ + m_i_string3_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +m_i_string4_test__rs* m_i_string4_test__cb(CORBA_Object oe_obj, + m_strRec** a, + m_strRec* b, + m_strRec** c, + CORBA_Environment *oe_env) +{ + *a = b; + *c = b; + + return (m_i_string4_test__rs*) NULL; +} + +/* OK */ +m_i_wstring1_test__rs* m_i_wstring1_test__cb(CORBA_Object oe_obj, + CORBA_wchar ** a, + CORBA_wchar * b, + CORBA_wchar ** c, + CORBA_Environment *oe_env) +{ + int tmp; + m_i_wstring1_test__rs* rs = NULL; + + /*printf("\nString in ------> %s\n\n",b);*/ + + for(tmp = 0; tmp < 5; tmp++) + fprintf(stderr,"\np[%d] = %ld\n", tmp, b[tmp]); + *a = b; + *c = b; + return rs; +} + + +/* OK */ +m_i_pid_test__rs* m_i_pid_test__cb(CORBA_Object oe_obj, + erlang_pid* a, + erlang_pid* b, + erlang_pid* c, + CORBA_Environment *oe_env) +{ + m_i_pid_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +/* OK */ +m_i_port_test__rs* m_i_port_test__cb(CORBA_Object oe_obj, + erlang_port* a, + erlang_port* b, + erlang_port* c, + CORBA_Environment *oe_env) +{ + m_i_port_test__rs* rs = NULL; + + strcpy((*a).node,(*b).node); + (*a).id = (*b).id; + (*a).creation = 0; + + strcpy((*c).node,(*b).node); + (*c).id = (*b).id; + (*c).creation = 0; + return rs; +} + +/* OK */ +m_i_ref_test__rs* m_i_ref_test__cb(CORBA_Object oe_obj, + erlang_ref* a, + erlang_ref* b, + erlang_ref* c, + CORBA_Environment *oe_env) +{ + + m_i_ref_test__rs* rs = NULL; + + strcpy((*a).node,(*b).node); + /*(*a).id = (*b).id;*/ + (*a).len = (*b).len; + (*a).n[0] = (*b).n[0]; + (*a).n[1] = (*b).n[1]; + (*a).n[2] = (*b).n[2]; + (*a).creation = 0; + + strcpy((*c).node,(*b).node); + /*(*c).id = (*b).id;*/ + (*c).len = (*b).len; + (*c).n[0] = (*b).n[0]; + (*c).n[1] = (*b).n[1]; + (*c).n[2] = (*b).n[2]; + (*c).creation = 0; + return rs; +} + +/* OK */ +m_i_term_test__rs* m_i_term_test__cb(CORBA_Object oe_obj, + ETERM** a, + ETERM** b, + ETERM** c, + CORBA_Environment *oe_env) +{ + m_i_term_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + +m_i_typedef_test__rs* m_i_typedef_test__cb(CORBA_Object oe_obj, + long* a, + ETERM** b, + erlang_port* c, + ETERM** d , + erlang_port* e, + CORBA_Environment *oe_env) +{ + m_i_typedef_test__rs* rs = NULL; + + *d = *b; + strcpy((*e).node,(*c).node); + (*e).id = (*c).id; + (*e).creation = 0; + *a = 4711; + return rs; +} + +/* OK */ +m_i_inline_sequence_test__rs* m_i_inline_sequence_test__cb( + CORBA_Object oe_obj, + m_s** a, + m_s* b, + m_s** c, + CORBA_Environment *oe_env) +{ + m_i_inline_sequence_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + +/* OK */ +m_i_term_sequence_test__rs* m_i_term_sequence_test__cb( + CORBA_Object oe_obj, + m_etseq** a, + m_etseq* b, + m_etseq** c, + CORBA_Environment *oe_env) +{ + m_i_term_sequence_test__rs* rs = NULL; + + *a = b; + *c = b; + return rs; +} + + +/* OK */ +m_i_term_struct_test__rs* m_i_term_struct_test__cb(CORBA_Object oe_obj, + m_et* a, + m_et* b, + m_et* c, + CORBA_Environment *oe_env) +{ + m_i_term_struct_test__rs* rs = NULL; + + *a = *b; + *c = *b; + return rs; +} + diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_c_test.idl b/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_c_test.idl new file mode 100644 index 0000000000..e90d0dd5f0 --- /dev/null +++ b/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_c_test.idl @@ -0,0 +1,174 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 2004-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +#include "erlang.idl" + + +const short TestConst = 1; + +module m { + + const short TestConst = 2; + + struct b { + long l; + char c; + }; + + struct simple { + long l; + b b_t; + }; + + enum fruit {orange, banana, apple, peach, pear}; + + typedef sequence<long> lseq; + + typedef sequence<b> bseq; + + struct a { + long l; + bseq y; + double d; + }; + + typedef sequence<a> aseq; + + typedef sequence<string> sseq; + typedef string str; + typedef long myLong; + + typedef long arr1[500], dd[2][3]; + + typedef erlang::term apa; + typedef erlang::port banan; + + typedef sequence<erlang::term> etseq; + + struct s { + long l; + sequence<long> sl; + }; + + struct es { + fruit f; + myLong l; + }; + + struct et { + erlang::term e; + long l; + }; + + + typedef sequence<char> str1; + typedef string<12> str2; + typedef char str3[3]; + + typedef sequence<string> sstr3; // sequence of string + typedef sequence<sstr3> ssstr3; // sequence of sequences of strings + + typedef long arr3[3]; // array of long + typedef sequence<arr3> sarr3; // sequence of array + typedef sequence<sarr3> ssarr3; // sequence of sequnces of arrays of strings + + struct strRec{ + boolean bb; + string str4; + long str7[3][2]; + sequence<char> str5; + string<12> str6; + str3 str8; + str2 str9; + str1 str10; + }; + + + struct dyn { + long l; + sequence<long> sl; + }; + typedef dyn arr2[1][2]; + + + interface i { + + const short TestConst = 3; + + //arr2 suck(in arr2 x, out arr2 y ); + + ///////////////////////////////// attribute long l; + + // simple types + void void_test(); + long long_test(in long a, out long a1); + long long longlong_test(in long long a, out long long a1); + unsigned short ushort_test(in unsigned short a, out unsigned short a1); + unsigned long ulong_test(in unsigned long a, out unsigned long a1); + unsigned long long ulonglong_test(in unsigned long long a, out unsigned long long a1); + double double_test(in double a, out double a1); + char char_test(in char a, out char a1); + wchar wchar_test(in wchar a, out wchar a1); + octet octet_test(in octet a, out octet a1); + boolean bool_test(in boolean a, out boolean a1); + + // Seq. and struct tests + b struct_test(in b a, out b a1); + es struct2_test(in es a, out es a1); + //simple struct3_test(in simple x, out simple y); + bseq seq1_test(in bseq a, out bseq a1); + aseq seq2_test(in aseq a, out aseq a1); + lseq seq3_test(in lseq a, out lseq a1); + ssstr3 seq4_test(in ssstr3 a, out ssstr3 a1); + ssarr3 seq5_test(in ssarr3 a, out ssarr3 a1); + + // Array tests + arr1 array1_test(in arr1 a, out arr1 a1); + dd array2_test(in dd a, out dd a1); + + // enum test + fruit enum_test(in fruit a, out fruit a1); + + // string tests + string string1_test(in string a, out string a1); + wstring wstring1_test(in wstring a, out wstring a1); + sseq string2_test(in sseq a, out sseq a1); + str string3_test(in str a, out str a1); + strRec string4_test(in strRec a, out strRec a1); + + // Special erlang types + erlang::pid pid_test(in erlang::pid a, out erlang::pid a1); + erlang::port port_test(in erlang::port a, out erlang::port a1); + erlang::ref ref_test(in erlang::ref a, out erlang::ref a1); + erlang::term term_test(in erlang::term a, out erlang::term a1); + + // typedef test + long typedef_test(in apa a, in banan b, out apa a1, out banan b1); + + // inlined seq. test + s inline_sequence_test(in s a, out s a1); + + // term seq. test + etseq term_sequence_test(in etseq a, out etseq a1); + // term struct test + et term_struct_test(in et a, out et a1); + + }; + +}; diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_client.erl b/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_client.erl new file mode 100644 index 0000000000..b5ee7af199 --- /dev/null +++ b/lib/ic/test/erl_client_c_server_proto_SUITE_data/erl_client.erl @@ -0,0 +1,331 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(erl_client). + +-export([void_test/2, long_test/2, longlong_test/2, ushort_test/2, + ulong_test/2, ulonglong_test/2, double_test/2, char_test/2, + wchar_test/2, octet_test/2, bool_test/2, struct_test/2, + struct2_test/2, seq1_test/2, seq2_test/2, seq3_test/2, + seq4_test/2, seq5_test/2, array1_test/2, array2_test/2, + enum_test/2, string1_test/2, wstring1_test/2, string2_test/2, + string3_test/2, string4_test/2, pid_test/2, port_test/2, + ref_test/2, term_test/2, typedef_test/2, + inline_sequence_test/2, term_sequence_test/2, + term_struct_test/2 + +]). + +-include("m.hrl"). +-include("m_i.hrl"). +-include("oe_erl_c_test.hrl"). + +%%b +void_test(Node, Timeout) -> + Ret = m_i:void_test({olsson, Node}, Timeout), + Ret == void. % XXX Not documented +%%e + +%%b +long_test(Node, Timeout) -> + In = max_long(), + {Ret, Out} = m_i:long_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +longlong_test(Node, Timeout) -> + In = 65537, + {Ret, Out} = m_i:longlong_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +ushort_test(Node, Timeout) -> + In = max_ushort(), + {Ret, Out} = m_i:ushort_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +ulong_test(Node, Timeout) -> + In = max_ulong(), + {Ret, Out} = m_i:ulong_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +ulonglong_test(Node, Timeout) -> + In = 65537, + {Ret, Out} = m_i:ulonglong_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +double_test(Node, Timeout) -> + In = 37768.93, + {Ret, Out} = m_i:double_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +char_test(Node, Timeout) -> + In = 80, + {Ret, Out} = m_i:char_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +wchar_test(Node, Timeout) -> + In = 4097, + {Ret, Out} = m_i:wchar_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +octet_test(Node, Timeout) -> + In = 255, + {Ret, Out} = m_i:octet_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +bool_test(Node, Timeout) -> + In = false, + {Ret, Out} = m_i:bool_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +struct_test(Node, Timeout) -> + In = #m_b{l = max_long(), c = $a}, + {Ret, Out} = m_i:struct_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +struct2_test(Node, Timeout) -> + In = #m_es{ f = banana, l = max_long()}, + {Ret, Out} = m_i:struct2_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +seq1_test(Node, Timeout) -> + B1 = #m_b{l = max_long(), c = $a}, + B2 = #m_b{l = min_long(), c = $b}, + In = [B1, B2], + {Ret, Out} = m_i:seq1_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +seq2_test(Node, Timeout) -> + B = #m_b{l = max_long(), c = $a}, + A = #m_a{l = min_long(), y = [B, B], d = 4711.31}, + In = [A, A, A], + {Ret, Out} = m_i:seq2_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +seq3_test(Node, Timeout) -> + In = [max_long(), min_long(), max_long()], + {Ret, Out} = m_i:seq3_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +seq4_test(Node, Timeout) -> + In = [["hej", "hopp"], ["ditt", "feta", "nylle"]], + {Ret, Out} = m_i:seq4_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +seq5_test(Node, Timeout) -> + Arr3 = mk_array(3, max_long()), + In = [[Arr3, Arr3], [Arr3, Arr3, Arr3]], + {Ret, Out} = m_i:seq5_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +array1_test(Node, Timeout) -> + In = mk_array(500, min_long()), + {Ret, Out} = m_i:array1_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +array2_test(Node, Timeout) -> + In = mk_array(2, mk_array(3, min_long())), + {Ret, Out} = m_i:array2_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +enum_test(Node, Timeout) -> + In = banana, + {Ret, Out} = m_i:enum_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +string1_test(Node, Timeout) -> + In = "Die Paula muss beim Tango immer weinen", + {Ret, Out} = m_i:string1_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +wstring1_test(Node, Timeout) -> + In = [1047| "ie Paula muss beim Tango immer weinen"], + {Ret, Out} = m_i:wstring1_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +string2_test(Node, Timeout) -> + In = ["Lass doch die Blumen,", "Konrad!"], + {Ret, Out} = m_i:string2_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +string3_test(Node, Timeout) -> + In = "Seeman, lass uns freuden!", + {Ret, Out} = m_i:string3_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +string4_test(Node, Timeout) -> + + In = #m_strRec{ + bb = true, + str4 = "Paula war zu Hause in ihrem Stadtchen als die beste Tanzerin" + "bekannt", + str7 = mk_array(3, mk_array(2, max_long())), + str5 = [$a, $b, $c, $d, $e, $f], + str6 = "123456789012", + str8 = {$x, $y, $x}, + str9 = "123456789012", + str10 = [$a, $b, $c, $d, $e, $f] + }, + {Ret, Out} = m_i:string4_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +pid_test(Node, Timeout) -> + In = self(), + {Ret, Out} = m_i:pid_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +port_test(Node, Timeout) -> + In = get(port_test_port), + {Ret, Out} = m_i:port_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +ref_test(Node, Timeout) -> + In = make_ref(), + {Ret, Out} = m_i:ref_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +term_test(Node, Timeout) -> + In = {[a, b], 17, kalle}, + {Ret, Out} = m_i:term_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +typedef_test(Node, Timeout) -> + In1 = {nisse, [1, 2], olsson}, + In2 = get(port_test_port), + {Ret, Out1, Out2} = m_i:typedef_test({olsson, Node}, Timeout, In1, In2), + %% XXX Should check that Ret is an integer. + (Out1 == In1) and (Out2 == In2). +%%e + +%%b +inline_sequence_test(Node, Timeout) -> + In = #m_s{l = min_long(), sl = [max_long(), min_long()]}, + {Ret, Out} = m_i:inline_sequence_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +term_sequence_test(Node, Timeout) -> + In = lists:duplicate(17, {nisse, [1, 2], {kalle, olsson}}), + {Ret, Out} = m_i:term_sequence_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + +%%b +term_struct_test(Node, Timeout) -> + In = #m_et{e = {nisse, ["abcde"], {kalle, olsson}}, l = 4711}, + {Ret, Out} = m_i:term_struct_test({olsson, Node}, Timeout, In), + (Ret == In) and (Out == In). +%%e + + +%% Locals + +mk_array(Es) -> + list_to_tuple(Es). + +mk_array(N, E) -> + mk_array(lists:duplicate(N, E)). + +%% max_short() -> +%% power_of_two(15) - 1. +max_long() -> + power_of_two(31) - 1. +max_longlong() -> + power_of_two(63) - 1. +max_ushort() -> + power_of_two(16) - 1. +max_ulong() -> + power_of_two(32) - 1. +max_ulonglong() -> + power_of_two(64) - 1. + +%% min_short() -> +%% -power_of_two(15). +min_long() -> + -power_of_two(31). +%% min_longlong() -> +%% -power_of_two(63). +%% min_ushort() -> +%% 0. +%% min_ulong() -> +%% 0. +%% min_ulonglong() -> +%% 0. + +power_of_two(N) -> + round(math:pow(2, N)). + diff --git a/lib/ic/test/erl_client_c_server_proto_SUITE_data/my.c b/lib/ic/test/erl_client_c_server_proto_SUITE_data/my.c new file mode 100644 index 0000000000..c0401b2621 --- /dev/null +++ b/lib/ic/test/erl_client_c_server_proto_SUITE_data/my.c @@ -0,0 +1,34 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2004-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +#include "ic.h" +#include "m_i.h" + +int my_prepare_request_decoding(CORBA_Environment *env) +{ + return oe_prepare_request_decoding(env); +} + +int my_prepare_reply_encoding(CORBA_Environment *env) +{ + return oe_prepare_reply_encoding(env); +} + + + diff --git a/lib/ic/test/ic.spec b/lib/ic/test/ic.spec new file mode 100644 index 0000000000..280c2aba47 --- /dev/null +++ b/lib/ic/test/ic.spec @@ -0,0 +1 @@ +{topcase, {dir, "../ic_test"}}. diff --git a/lib/ic/test/ic.spec.vxworks b/lib/ic/test/ic.spec.vxworks new file mode 100644 index 0000000000..b15260ab70 --- /dev/null +++ b/lib/ic/test/ic.spec.vxworks @@ -0,0 +1,2 @@ +{topcase, {dir, "../ic_test"}}. +{skip,{ic_pp_SUITE,"Uses gcc"}}. diff --git a/lib/ic/test/ic_SUITE.erl b/lib/ic/test/ic_SUITE.erl new file mode 100644 index 0000000000..6682c82f01 --- /dev/null +++ b/lib/ic/test/ic_SUITE.erl @@ -0,0 +1,973 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%%---------------------------------------------------------------------- +%%% Purpose : Test suite for the IDL compiler +%%%---------------------------------------------------------------------- + +-module(ic_SUITE). +-include("test_server.hrl"). + +-export([all/1]). + + +-include_lib("orber/src/orber_ifr.hrl"). +-include_lib("orber/src/ifr_objects.hrl"). +-include_lib("orber/include/ifr_types.hrl"). + + +%% The type cases +-export([type/1, type_norm/1]). + +%% The syntax case +-export([syntax/1]). +-export([syntax1/1, syntax2/1, syntax3/1, syntax4/1, syntax5/1, syntax6/1]). + +%% The constant cases +-export([const/1]). +-export([const_norm/1, const_bad_tk/1, const_bad_type/1]). +-export([const_bad_comb/1]). + +%% The union cases +-export([union/1]). +-export([union_norm/1, union_type/1, union_mult_err/1, union_case_mult/1]). +-export([union_default/1]). + +%% The enum cases +-export([enum/1]). +-export([enum_norm/1]). + +%% The struct cases +-export([struct/1]). +-export([struct_norm/1]). + +%% The oneway cases +-export([oneway/1]). +-export([oneway_norm/1, oneway_raises/1, oneway_out/1, oneway_void/1, oneway_followed/1]). + +%% The attributes cases +-export([attr/1]). +-export([attr_norm/1]). + +%% The raises registration case +-export([raises_reg/1]). + + +%% The typeID case + +%% general stuff +-export([general/1]). +-export([typeid/1, undef_id/1, dir/1, nasty_names/1, coss/1, mult_ids/1]). +-export([forward/1, include/1, app_test/1]). + +%% inheritance stuff +-export([inherit/1, inherit_norm/1, inherit_warn/1, inherit_err/1]). + +%% Standard options to the ic compiler, NOTE unholy use of OutDir + +-define(OUT(X), filename:join([?config(priv_dir, Config), gen, to_list(X)])). + + +%% Top of cases + +all(doc) -> + []; +all(suite) -> [app_test, const, union, enum, attr, type, struct, general, inherit, + oneway, syntax, raises_reg]. + + +app_test(doc) -> []; +app_test(suite) -> []; +app_test(_Config) -> + ok=test_server:app_test(ic), + ok. + +%%--------------------------------------------------------------------- +%% +%% Test of constant expressions. +%% + +const(suite) -> [const_norm, const_bad_tk, const_bad_type, const_bad_comb]. + + +const_norm(doc) -> + ["Checks normal constant types and values"]; +const_norm(suite) -> []; +const_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(const_norm), + File = filename:join(DataDir, c_norm), + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, const_norm_files()), + ok. + +const_bad_tk(doc) -> + ["Checks when the constant value doesn't match the declared type"]; +const_bad_tk(suite) -> []; +const_bad_tk(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, c_err1), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(18, bad_tk_match, R), + ok. + +const_bad_type(doc) -> + ["Checks operands of ops are of correct type"]; +const_bad_type(suite) -> []; +const_bad_type(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, c_err2), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(4, bad_type, R), + ok. + +const_bad_comb(doc) -> + ["Checks operands of ops are of conflicting types"]; +const_bad_comb(suite) -> []; +const_bad_comb(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, c_err3), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(3, bad_type_combination, R), + ok. + + + +union(suite) -> [union_norm, union_type, union_mult_err, union_case_mult, + union_default]; +union(doc) -> + ["Checks allowed usage of the union as well as the illegal cases"]. + + +union_norm(doc) -> + ["Checks that normal union declarations works."]; +union_norm(suite) -> []; +union_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(union_norm), + File = filename:join(DataDir, u_norm), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, union_norm_files()), + ok. + + +%% Checks OTP-2007 +union_default(doc) -> + ["Checks that default cases are correct in type code."]; +union_default(suite) -> []; +union_default(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(union_default), + File = filename:join(DataDir, u_default), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, union_default_files(), [load]), + TkList = i1:oe_get_interface(), + check_label("op0", 0, TkList), + check_label("op1", 1, TkList), + check_label("op2", 2, TkList), + check_label("op3", -1, TkList), + ok. + +check_label(Id, N, List) -> + case lists:keysearch(Id, 1, List) of + {value, {_, {{_, _, _, _, D, L}, _, _}}} -> + if D /= N -> + test_server:fail({bad_default_num, D, N}); + D /= -1 -> + case lists:nth(D+1, L) of + T when element(1, T) == default -> + ok; + _Que -> + test_server:fail({bad_default_list, D, L}) + end; + true -> + %% D = N = -1, just check that there is no default label + case lists:keysearch(default, 1, L) of + false -> + ok; + _ -> + test_server:fail({bad_default_label, D, L}) + end + end; + _ -> + test_server:fail({'no_such_op!', Id, List}) + end. + +union_type(doc) -> + ["Checks that errors are detected. Check that mismatch between case ", + "value and declared discriminator type is detected."]; +union_type(suite) -> []; +union_type(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, u_type), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(28, bad_case_type, R), + ok. + + +union_mult_err(doc) -> + ["Check that multiple declared declarators are caught.", + "Also check that if the discriminator is an enum, then the enum name", + "must not be used as a declarator in the union switch (declarator", + "as opposed to label)."]; +union_mult_err(suite) -> []; +union_mult_err(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, u_mult), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(8, multiply_defined, R), + ok. + +%% Checking mult cases. Now check that other errors are found in the +%% correct order XXXX + + +union_case_mult(doc) -> + ["Check that multiply defined case labels are found and reported."]; +union_case_mult(suite) -> []; +union_case_mult(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, u_case_mult), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(7, multiple_cases, R), + ok. + + +%%-------------------------------------------------------------------- +%% +%% Enum cases +%% + +enum(suite) -> [enum_norm]; +enum(doc) -> + ["Checks allowed usage of the enum as well as the illegal cases"]. + +enum_norm(doc) -> + ["Checks that normal enum declarations works."]; +enum_norm(suite) -> []; +enum_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(enum_norm), + File = filename:join(DataDir, enum), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, enum_norm_files()), + ok. + + +%%-------------------------------------------------------------------- +%% +%% Struct cases +%% + +struct(suite) -> [struct_norm]; +struct(doc) -> + ["Checks allowed usage of the struct as well as the illegal cases"]. + +struct_norm(doc) -> + ["Checks that normal struct declarations works."]; +struct_norm(suite) -> []; +struct_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(struct_norm), + File = filename:join(DataDir, struct), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, struct_norm_files()), + Mod = ridiculous_name_to_avoid_clash_svenne, + TestFile = filename:join(OutDir, Mod), + ?line ok = gen_struct_file(TestFile, Mod), + ?line ok = compile(OutDir, [Mod], [load]), +%% ?line {ok, Mod, []} = compile:file(TestFile, +%% [{i, OutDir}, {outdir, OutDir}, +%% return, load]), + ?line ok = Mod:test(), + ok. + + +%%-------------------------------------------------------------------- +%% +%% General cases +%% + +general(doc) -> + ["Check general things like directories and type identifier", + "detection."]; +general(suite) -> [typeid, undef_id, mult_ids, forward, include, nasty_names]. +%% coss (add sometimes, takes 440 seconds!) + +typeid(doc) -> + ["Check that type id's are generated correctly"]; +typeid(suite) -> []; +typeid(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(typeid), + File = filename:join(DataDir, typeid), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, typeid_files(), [load]), + ?line "IDL:I1:1.0" = 'I1':'typeID'(), + ?line "IDL:M1/I1:1.0" = 'M1_I1':'typeID'(), + ?line "IDL:M2/M1/I1:1.0" = 'M2_M1_I1':'typeID'(), + ?line "IDL:M3/M2/M1/I1:1.0" = 'M3_M2_M1_I1':'typeID'(), + ok. + + +%%% This test case is removed because there's no way to test this from +%%% an automated test suite. +dir(doc) -> + ["Check that relative directories work, absolute is used in", + "all other cases in the suite."]; +%%% xxxxxx +dir(suite) -> []; +dir(Config) when is_list(Config) -> +ok; +dir(Config) -> + DataDir = ?config(data_dir, Config), + + %% Needs a unique directory (any better way?) + OutDir = mk_unique("oe_the_dir"), + + %% More unique names + File = filename:join(DataDir, mk_unique("oe_the_file")), + Const = mk_unique("oe_the_constant"), + Mod = list_to_atom(File), + Func = list_to_atom(Const), + + %% Generate a unique IDL file with a single constant + gen_file(File, Const), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line ok = compile(OutDir, [load]), + ?line 19955 = Mod:Func(), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, [load]), + ?line 19955 = Mod:Func(), + + ?line ok = ic:gen(File), +%%% ?line ok = compile(".", [load]), + ok. + +undef_id(doc) -> + ["Check that various undefied id's are detected correctly"]; +undef_id(suite) -> []; +undef_id(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, undef_id), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(16, tk_not_found, R), + ok. + +mult_ids(doc) -> + ["Check that multiply defined ids are caught."]; +mult_ids(suite) -> []; +mult_ids(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, mult_ids), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(22, multiply_defined, R), + ok. + + +nasty_names(doc) -> + ["Check that various nasty names can be generated.", + "Try to provoke name clashes and name conflicts with", + "Erlang and IDL"]; +nasty_names(suite) -> []; +nasty_names(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(nasty_names), + File = filename:join(DataDir, nasty), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, nasty_names_files(), [load]), + ok. + +coss(doc) -> + ["Check that the Coss standard specification works."]; +coss(suite) -> []; +coss(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(coss), + File = filename:join(DataDir, 'Coss'), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, [_W1]} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, []), + ok. + +forward(doc) -> + ["Check that forward declaratios work."]; +forward(suite) -> []; +forward(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(forward), + File = filename:join(DataDir, forward), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, forward_files(), [load]), + ok. + +include(doc) -> + ["Check that various undefied id's are detected correctly"]; +include(suite) -> []; +include(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, include), + ?line error = ic:gen(File, stdopts(OutDir)++[{preproc_flags,"-I" ++ DataDir}]), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[{preproc_flags,"-I" ++ DataDir},silent2]), + case lists:map(fun(D) -> + filename:rootname(filename:basename(element(3, D))) + end, + lists:sort(R)) of + ["include", + "include2", + "include2", + "include3"] -> + ok; + RRR -> + test_server:fail({bad_include_file, RRR}) + end, + ok. + + + + +%%-------------------------------------------------------------------- +%% +%% Inhertit cases +%% + +inherit(doc) -> + ["Check the inheritance mechanism."]; +inherit(suite) -> [inherit_norm, inherit_warn, inherit_err]. + +inherit_norm(doc) -> + ["Checks that normal inheritance works."]; +inherit_norm(suite) -> []; +inherit_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(inherit_norm), + File = filename:join(DataDir, inherit), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, _Ws} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, inherit_norm_files(), [load]), + + %% Now check constant values: + ?line 9 = m1_I1:c1(), + + ?line 9 = m1_I2:c1(), + ?line 14 = m1_I2:c2(), + ?line 27 = m1_I2:c3(), + + ?line 50 = m1_I3:c1(), + ?line 14 = m1_I3:c2(), + ?line 27 = m1_I3:c3(), + ?line 91 = m1_I3:c4(), + ?line 100 = m1_I3:c5(), + ok. + +inherit_warn(doc) -> + ["Check that various inheritance shadowing is detected"]; +inherit_warn(suite) -> []; +inherit_warn(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, inherit_warn), + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(7, inherit_name_shadow, R), + ok. + +inherit_err(doc) -> + ["Check that various inheritance errors is detected"]; +inherit_err(suite) -> []; +inherit_err(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, inherit_err), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, _Ws, R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(21, inherit_name_collision, R), + ok. + + +oneway(doc) -> + ["Check the oneway operation mechanism."]; +oneway(suite) -> [oneway_norm, oneway_out, oneway_raises, oneway_void, oneway_followed ]. + +oneway_norm(doc) -> + ["Checks that normal oneway operations works."]; +oneway_norm(suite) -> []; +oneway_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(oneway_norm), + File = filename:join(DataDir, one), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line ok = compile(OutDir, oneway_norm_files(), [load]), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, oneway_norm_files(), [load]), + ok. + +oneway_void(doc) -> + ["Check that non-void oneways are detected."]; +oneway_void(suite) -> []; +oneway_void(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, one_void), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(2, bad_oneway_type, R), + ok. + +oneway_raises(doc) -> + ["Check that oneways cannot raise exceptions."]; +oneway_raises(suite) -> []; +oneway_raises(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, one_raises), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(3, oneway_raises, R), + ok. + +oneway_out(doc) -> + ["Check that illegal out parameters are detected"]; +oneway_out(suite) -> []; +oneway_out(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, one_out), + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(2, oneway_outparams, R), + ok. + +oneway_followed(doc) -> + ["Checks that normal oneways, followed by other operations."]; +oneway_followed(suite) -> []; +oneway_followed(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(oneway_followed), + File = filename:join(DataDir, one_followed), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line ok = compile(OutDir, oneway_followed_files(), [load]), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, oneway_followed_files(), [load]), + ok. + +attr(doc) -> + ["Check that attributes work."]; +attr(suite) -> [attr_norm]. + +attr_norm(doc) -> + ["Checks that normal attr operations works."]; +attr_norm(suite) -> []; +attr_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(attr_norm), + File = filename:join(DataDir, attr), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line ok = compile(OutDir, attr_norm_files(), [load]), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, attr_norm_files(), [load]), + ok. + +type(doc) -> + ["Check that typeibutes work."]; +type(suite) -> [type_norm]. + +type_norm(doc) -> + ["Checks all types are handled."]; +type_norm(suite) -> []; +type_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(type_norm), + File = filename:join(DataDir, type), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line ok = compile(OutDir, type_norm_files(), [load]), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, type_norm_files(), [load]), + ok. + + +syntax(doc) -> + ["Check that syntax errors are discovered."]; +syntax(suite) -> [syntax1, syntax2, syntax3, syntax4, syntax5, syntax6]. + +syntax1(suite) -> []; +syntax1(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, syntax1), + + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(1, parse_error, R), + ok. + +syntax2(suite) -> []; +syntax2(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, syntax2), + + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(1, parse_error, R), + ok. + +syntax3(suite) -> []; +syntax3(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, syntax3), + + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(1, parse_error, R), + ok. + +syntax4(suite) -> []; +syntax4(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, syntax4), + + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(1, parse_error, R), + ok. + +syntax5(suite) -> []; +syntax5(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, syntax5), + + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(1, parse_error, R), + ok. + +syntax6(suite) -> []; +syntax6(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, syntax6), + + ?line error = ic:gen(File, stdopts(OutDir)), + ?line {error, [], R} = + ic:gen(File, stdopts(OutDir)++[silent2]), + check_errors(1, parse_error, R), + ok. + + + +%%-------------------------------------------------------------------- +%% +%% Checks RAISES to be registered under IFR operation registration +%% ( OTP-2102 ) +%% + +raises_reg(doc) -> + ["Check that exceptions are really registered to operations."]; +raises_reg(suite) -> []; +raises_reg(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(raises_reg_check), + File = filename:join(DataDir, raises_reg), + + ?line ok = ic:gen(File, stdopts(OutDir)), + ?line {ok, []} = ic:gen(File, stdopts(OutDir)++[silent2]), + ?line ok = compile(OutDir, raises_reg_files(), [load]), + + set_up('oe_raises_reg'), + + io:format("~n##### Starting the test case #####~n"), + io:format("Checking for existance of exception : ~s~n",["IDL:Raises_RegModule/Exception_1:1.0"]), + raises_register_check("IDL:Raises_RegModule/R_R/op:1.0","IDL:Raises_RegModule/Exception_1:1.0"), + + io:format("Checking for existance of exception : ~s~n",["IDL:Raises_RegModule/Exception_2:1.0"]), + raises_register_check("IDL:Raises_RegModule/R_R/op:1.0","IDL:Raises_RegModule/Exception_2:1.0"), + + io:format("Checking for existance of exception : ~s~n",["IDL:Raises_RegModule/XXXXXXXX:1.0"]), + raises_register_check("IDL:Raises_RegModule/R_R/op:1.0","IDL:RaisesModule/XXXXXXXX:1.0"), + + set_down('oe_raises_reg'), + + ok. + +set_up(Register) -> + io:format("Setting up.....~n"), + mnesia:stop(), + mnesia:delete_schema([node()]), + mnesia:create_schema([node()]), + mnesia:start(), + orber:install([node()]), + orber:start(), + io:format("Running OE_register()~n"), + Register:'oe_register'(). + +set_down(Register) -> + io:format("Running OE_unregister()~n"), + Register:'oe_unregister'(), + io:format("Setting down.....~n"), + orber:stop(), + orber:uninstall(), + mnesia:stop(), + mnesia:delete_schema([node()]). + + +raises_register_check(OpId,ExcId) -> + case is_valid_exc(OpId,ExcId) of + true -> + ok; % Because right exception where found, + % the test succeeds for normal cases. + false -> + ok; % Because the exception tested, is not + % registered for that operation. + FailReason -> + test_server:fail({FailReason, OpId, ExcId}) + % Because the test descovered errors in a previous + % stage, or no exceptions where registered att all. + % ( This testcase assumes that operations to be + % checked allways raise excption(s) ) + end. + +is_valid_exc(OpId,ExcId) -> + OE_IFR = orber_ifr:find_repository(), + OpDef = orber_ifr:'Repository_lookup_id'(OE_IFR,OpId), + ExcDefList = orber_ifr:get_exceptions(OpDef), + case ExcDefList of + [] -> + no_exceptions_registered; + _ -> + ExcDef=orber_ifr:lookup_id(OE_IFR,ExcId), + lists:member(ExcDef,ExcDefList) + end. + +%%-------------------------------------------------------------------- +%% +%% Utilities + + +stdopts(OutDir) -> + [{outdir, OutDir},{maxerrs, infinity}]. + +mk_unique(Prefix) -> + {A,B,C} = now(), + Prefix++"_"++integer_to_list(A)++"_"++integer_to_list(B)++"_"++ + integer_to_list(C). + +gen_file(File, Const) -> + {ok, Fd} = file:open(File++".idl", [write]), + io:format(Fd, "interface ~s {~n", [File]), + io:format(Fd, " const long ~s = 19955;~n", [Const]), + io:format(Fd, "};~n", []), + file:close(Fd). + + +%% Compile all files in Dir. Used for checking that valid Erlang has +%% been generated. +%%compile(Dir) -> +%% compile(Dir, []). +%%compile(Dir, Opts) -> +%% {ok, Cwd} = file:get_cwd(), +%% catch do_compile(Dir, Opts), +%% file:set_cwd(Cwd). + +%%do_compile(Dir, Opts) -> +%% ok = file:set_cwd(Dir), +%% up_to_date = ts_make_erl:all(Opts), +%% ok. + +compile(Dir, Files) -> + compile(Dir, Files, []). + +compile(Dir, Files, Opts) -> + {ok, Cwd} = file:get_cwd(), + file:set_cwd(Dir), + io:format("Changing to ~p~n", [Dir]), + case catch do_compile(Files, Opts) of + ok -> + file:set_cwd(Cwd); + Err -> + file:set_cwd(Cwd), + test_server:fail(Err) + end. + +do_compile([], _Opts) -> ok; +do_compile([F | Fs], Opts) -> + io:format("Compiling ~p", [F]), + case compile:file(F, Opts) of + ok -> + io:format(" ok~n", []), + do_load(F, Opts), + do_compile(Fs, Opts); + {ok, _} -> + io:format(" ok~n", []), + do_load(F, Opts), + do_compile(Fs, Opts); + {ok, _, _} -> + io:format(" ok~n", []), + do_load(F, Opts), + do_compile(Fs, Opts); + Err -> + io:format(" error: ~p~n", [Err]), + Err + end. + +do_load(File, Opts) -> + case lists:member(load, Opts) of + true -> + io:format("Loading file ~p", [File]), + code:purge(File), + R = code:load_abs(File), + io:format("Loaded: ~p", [R]); + false -> + ok + end. + + +%% Check that ErrList consists of exactly Num errors of type ErrType +check_errors(Num, ErrType, ErrList) -> + Num = length(ErrList), + lists:foreach(fun(T) -> + case catch element(1, element(4, T)) of + ErrType -> ok; + Else -> + test_server:fail({bad, ErrType, Else}) + end end, ErrList). + +to_list(X) when is_atom(X) -> atom_to_list(X); +to_list(X) -> X. + + +%% File must be an atom +gen_struct_file(File, Mod) -> + + ?line {ok, Fd} = file:open(to_list(File)++".erl", [write]), + io:format(Fd, "~n", []), + io:format(Fd, "-module(~p).~n", [Mod]), + io:format(Fd, "-export([test/0]).~n", []), + io:format(Fd, "-include(\"oe_struct.hrl\").~n", []), + io:format(Fd, "test() ->~n", []), + io:format(Fd, " A = #'S1'{a=99, b=$a, s=\"123456789\"},~n", []), + io:format(Fd, " B = #'S2'{a=9, b=#'S2_S3'{a=1, b=9, b1=5, c=$2},~n", []), + io:format(Fd, " c=[#'S1'{a=1}, #'S1'{a=2}],~n", []), + io:format(Fd, +" c2=[#'S1'{a=2}, #'S1'{a=3}, #'S1'{a=2}, #'S1'{a=3}]},~n", []), + io:format(Fd, " C = #'S2_S3'{a=11, b=999, b1=19},~n", []), + io:format(Fd, " D = #s4{a=7},~n", []), + io:format(Fd, " E = {1, #'U1_S5'{a=3}},~n", []), + io:format(Fd, " F = {2, {$b, #'U1_U2_s6'{a=6, b=false}}},~n", []), + io:format(Fd, " ok.~n", []), + file:close(Fd). + + +union_norm_files() -> ['oe_u_norm']. +union_default_files() -> ['oe_u_default', i1]. + +typeid_files() -> ['oe_typeid', 'M3_M2_M1_I1', 'M2_M1_I1', 'M1_I1', 'I1']. + +struct_norm_files() -> ['oe_struct']. +oneway_norm_files() -> ['oe_one', 'I1']. +oneway_followed_files() -> ['oe_one_followed', 'I1']. +nasty_names_files() -> ['oe_nasty', 'I2', 'I1']. + +inherit_norm_files() -> [m1_I3, m1_I2, m1_I1, 'oe_inherit', 'I4', 'I3', + 'I2', 'I1']. + +forward_files() -> [i1, 'oe_forward']. +enum_norm_files() -> ['oe_enum']. +const_norm_files() -> ['oe_c_norm']. +attr_norm_files() -> ['oe_attr', 'I1', 'I2']. +type_norm_files() -> ['oe_type']. + +raises_reg_files() -> ['oe_raises_reg']. + + + + + + + + + + + + + + + + diff --git a/lib/ic/test/ic_SUITE_data/Corba.idl b/lib/ic/test/ic_SUITE_data/Corba.idl new file mode 100644 index 0000000000..6b81132500 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/Corba.idl @@ -0,0 +1,1013 @@ +// This file contains OMG IDL from CORBA V2.0, July 1995. +// Includes IDL for CORBA Core +// (Interface Repository, ORB Interface, Basic Object Adapter Interface) +// and CORBA Interoperability (IOP, GIOP, IIOP, and DCE CIOP modules) + +// Complete OMG IDL for Interface Repository starts on pg 6-42, CORBA V2.0 July 1995 +// IRObject interface described on pg 6-9 CORBA V2.0, July 1995 +// Contained interface: pg 6-11 CORBA V2, 7-95 +// Container interface: pg 6-12 thru 6-15 CORBA V2, 7-95 +// IDLType interface: pg 6-15 CORBA V2, 7-95 +// Repository interface: pg 6-16 CORBA V2, 7-95 +// ModuleDef interface: pg 6-17 CORBA V2, 7-95 +// ConstantDef interface: pg 6-18 CORBA V2, 7-95 +// TypeDef interface: pg 6-19 CORBA V2, 7-95 +// StructDef interface: pg 6-19 CORBA V2, 7-95 +// UnionDef interface: pg 6-19 CORBA V2, 7-95 +// EnumDef interface: pg 6-20 CORBA V2, 7-95 +// AliasDef interface: pg 6-21 CORBA V2, 7-95 +// PrimitiveDef interface: pg 6-21 CORBA V2, 7-95 +// StringDef interface: pg 6-22 CORBA V2, 7-95 +// SequenceDef interface: pg 6-22 CORBA V2, 7-95 +// ArrayDef interface: pg 6-23 CORBA V2, 7-95 +// ExceptionDef interface: pg 6-24 CORBA V2, 7-95 +// AttributeDef interface: pg 6-25 CORBA V2, 7-95 +// OperationDef interface: pg 6-26 CORBA V2, 7-95 +// InterfaceDef interface: pg 6-28 CORBA V2, 7-95 +// TypeCode interface (PIDL): pg 6-34 CORBA V2, 7-95 +// ORB interface: pg 6-40 CORBA V2, 7-95 + +#ifndef __CORBA_IDL +#define __CORBA_IDL + +// #pragma prefix "omg.org" +module CORBA { + + interface TypeCode; + typedef string Identifier; + typedef string ScopedName; + typedef string RepositoryId; + + /* + * start of section added by Christian Blum + */ + + typedef enum new_type {NO,USER,SYSTEM_EXCEPTION} exception_type; + + /** + * no definition for this type + */ + interface ImplementationDef + { + }; + + /** + * no definition for this type + */ + //interface Principal + struct Principal + { + string str; + }; + + /** + * no definition for this type + */ + interface Environment + { + + }; + + typedef unsigned long Flags; + typedef unsigned long Status; + + struct NamedValue // PIDL + { + Identifier name; // argument name + any argument; // argument + long len; // length/count of argument value + Flags arg_modes; // argument mode flags + + }; + + typedef sequence<NamedValue> NVList; /* C */ + + interface Request // PIDL + { + + Status add_arg ( + in Identifier name, // argument name + in TypeCode arg_type, // argument datatype + // in void * value, // argument value to be added + in any value_LOOK_AT_SOURCE, // changed by blum + in long len, // length/count of argument value + in Flags arg_flags // argument flags + ); + + Status invoke ( + in Flags invoke_flags // invocation flags + ); + + Status delete (); + Status send ( + in Flags invoke_flags // invocation flags + ); + + Status get_response ( + in Flags response_flags // response flags + ); + + }; + + + interface Context // PIDL + { + + Status set_one_value ( + in Identifier prop_name, // property name to add + in string value // property value to add + ); + + Status set_values ( + in NVList values // property values to be changed + ); + + Status get_values ( + in Identifier start_scope, // search scope + in Flags op_flags, // operation flags + in Identifier prop_name, // name of property(s) to retrieve + out NVList values // requested property(s) + ); + + Status delete_values ( + in Identifier prop_name // name of property(s) to delete + ); + + Status create_child ( + in Identifier ctx_name, // name of context object + out Context child_ctx // newly created context object + ); + + Status delete ( + in Flags del_flags // flags controlling deletion + ); + + }; + + /* + * end of section added by Christian Blum + */ + + + enum DefinitionKind { + dk_none, dk_all, + dk_Attribute, dk_Constant, dk_Exception, dk_Interface, + dk_Module, dk_Operation, dk_Typedef, + dk_Alias, dk_Struct, dk_Union, dk_Enum, + dk_Primitive, dk_String, dk_Sequence, dk_Array, + dk_Repository + }; + + + interface IRObject { + // read interface + readonly attribute DefinitionKind def_kind; + + // write interface + void destroy (); + }; + + + + typedef string VersionSpec; + + interface Contained; + interface Repository; + interface Container; + + interface Contained : IRObject { + // read/write interface + + attribute RepositoryId id; + attribute Identifier name; + attribute VersionSpec version; + + // read interface + + readonly attribute Container defined_in; + readonly attribute ScopedName absolute_name; + readonly attribute Repository containing_repository; + + struct Description { + DefinitionKind kind; + any value; + }; + + Description describe (); + + // write interface + + void move ( + in Container new_container, + in Identifier new_name, + in VersionSpec new_version + ); + }; + + + interface ModuleDef; + interface ConstantDef; + interface IDLType; + interface StructDef; + interface UnionDef; + interface EnumDef; + interface AliasDef; + interface InterfaceDef; + typedef sequence <InterfaceDef> InterfaceDefSeq; + + typedef sequence <Contained> ContainedSeq; + + struct StructMember { + Identifier name; + TypeCode type; + IDLType type_def; + }; + typedef sequence <StructMember> StructMemberSeq; + + struct UnionMember { + Identifier name; + any label; + TypeCode type; + IDLType type_def; + }; + typedef sequence <UnionMember> UnionMemberSeq; + + typedef sequence <Identifier> EnumMemberSeq; + + interface Container : IRObject { + // read interface + + Contained lookup ( in ScopedName search_name); + + ContainedSeq contents ( + in DefinitionKind limit_type, + in boolean exclude_inherited + ); + + ContainedSeq lookup_name ( + in Identifier search_name, + in long levels_to_search, + in DefinitionKind limit_type, + in boolean exclude_inherited + ); + + struct Description { + Contained contained_object; + DefinitionKind kind; + any value; + }; + + typedef sequence<Description> DescriptionSeq; + + DescriptionSeq describe_contents ( + in DefinitionKind limit_type, + in boolean exclude_inherited, + in long max_returned_objs + ); + + // write interface + + ModuleDef create_module ( + in RepositoryId id, + in Identifier name, + in VersionSpec version + ); + + ConstantDef create_constant ( + in RepositoryId id, + in Identifier name, + in VersionSpec version, + in IDLType type, + in any value + ); + + StructDef create_struct ( + in RepositoryId id, + in Identifier name, + in VersionSpec version, + in StructMemberSeq members + ); + + UnionDef create_union ( + in RepositoryId id, + in Identifier name, + in VersionSpec version, + in IDLType discriminator_type, + in UnionMemberSeq members + ); + + EnumDef create_enum ( + in RepositoryId id, + in Identifier name, + in VersionSpec version, + in EnumMemberSeq members + ); + + AliasDef create_alias ( + in RepositoryId id, + in Identifier name, + in VersionSpec version, + in IDLType original_type + ); + + InterfaceDef create_interface ( + in RepositoryId id, + in Identifier name, + in VersionSpec version, + in InterfaceDefSeq base_interfaces + ); + }; + + + + interface IDLType : IRObject { + readonly attribute TypeCode type; + }; + + + + interface PrimitiveDef; + interface StringDef; + interface SequenceDef; + interface ArrayDef; + + enum PrimitiveKind { + pk_null, pk_void, pk_short, pk_long, pk_ushort, pk_ulong, + pk_float, pk_double, pk_boolean, pk_char, pk_octet, + pk_any, pk_TypeCode, pk_Principal, pk_string, pk_objref + }; + + interface Repository : Container { + // read interface + + Contained lookup_id (in RepositoryId search_id); + + PrimitiveDef get_primitive (in PrimitiveKind kind); + + // write interface + + StringDef create_string (in unsigned long bound); + + SequenceDef create_sequence ( + in unsigned long bound, + in IDLType element_type + ); + + ArrayDef create_array ( + in unsigned long length, + in IDLType element_type + ); + }; + + + interface ModuleDef : Container, Contained { + }; + + struct ModuleDescription { + Identifier name; + RepositoryId id; + RepositoryId defined_in; + VersionSpec version; + }; + + + interface ConstantDef : Contained { + readonly attribute TypeCode type; + attribute IDLType type_def; + attribute any value; + }; + + struct ConstantDescription { + Identifier name; + RepositoryId id; + RepositoryId defined_in; + VersionSpec version; + TypeCode type; + any value; + }; + + + interface TypedefDef : Contained, IDLType { + }; + + struct TypeDescription { + Identifier name; + RepositoryId id; + RepositoryId defined_in; + VersionSpec version; + TypeCode type; + }; + + + interface StructDef : TypedefDef { + attribute StructMemberSeq members; + }; + + + interface UnionDef : TypedefDef { + readonly attribute TypeCode discriminator_type; + attribute IDLType discriminator_type_def; + attribute UnionMemberSeq members; + }; + + + interface EnumDef : TypedefDef { + attribute EnumMemberSeq members; + }; + + + interface AliasDef : TypedefDef { + attribute IDLType original_type_def; + }; + + + interface PrimitiveDef: IDLType { + readonly attribute PrimitiveKind kind; + }; + + + interface StringDef : IDLType { + attribute unsigned long bound; + }; + + + interface SequenceDef : IDLType { + attribute unsigned long bound; + readonly attribute TypeCode element_type; + attribute IDLType element_type_def; + }; + + interface ArrayDef : IDLType { + attribute unsigned long length; + readonly attribute TypeCode element_type; + attribute IDLType element_type_def; + }; + + + interface ExceptionDef : Contained { + readonly attribute TypeCode type; + attribute StructMemberSeq members; + }; + struct ExceptionDescription { + Identifier name; + RepositoryId id; + RepositoryId defined_in; + VersionSpec version; + TypeCode type; + }; + + + + enum AttributeMode {ATTR_NORMAL, ATTR_READONLY}; + + interface AttributeDef : Contained { + readonly attribute TypeCode type; + attribute IDLType type_def; + attribute AttributeMode mode; + }; + + struct AttributeDescription { + Identifier name; + RepositoryId id; + RepositoryId defined_in; + VersionSpec version; + TypeCode type; + AttributeMode mode; + }; + + + + enum OperationMode {OP_NORMAL, OP_ONEWAY}; + + enum ParameterMode {PARAM_IN, PARAM_OUT, PARAM_INOUT}; + struct ParameterDescription { + Identifier name; + TypeCode type; + IDLType type_def; + ParameterMode mode; + }; + typedef sequence <ParameterDescription> ParDescriptionSeq; + + typedef Identifier ContextIdentifier; + typedef sequence <ContextIdentifier> ContextIdSeq; + + typedef sequence <ExceptionDef> ExceptionDefSeq; + typedef sequence <ExceptionDescription> ExcDescriptionSeq; + + interface OperationDef : Contained { + readonly attribute TypeCode result; + attribute IDLType result_def; + attribute ParDescriptionSeq params; + attribute OperationMode mode; + attribute ContextIdSeq contexts; + attribute ExceptionDefSeq exceptions; + }; + + struct OperationDescription { + Identifier name; + RepositoryId id; + RepositoryId defined_in; + VersionSpec version; + TypeCode result; + OperationMode mode; + ContextIdSeq contexts; + ParDescriptionSeq parameters; + ExcDescriptionSeq exceptions; + }; + + + + typedef sequence <RepositoryId> RepositoryIdSeq; + typedef sequence <OperationDescription> OpDescriptionSeq; + typedef sequence <AttributeDescription> AttrDescriptionSeq; + + interface InterfaceDef : Container, Contained, IDLType { + // read/write interface + + attribute InterfaceDefSeq base_interfaces; + + // read interface + + boolean is_a (in RepositoryId interface_id); + + struct FullInterfaceDescription { + Identifier name; + RepositoryId id; + RepositoryId defined_in; + VersionSpec version; + OpDescriptionSeq operations; + AttrDescriptionSeq attributes; + RepositoryIdSeq base_interfaces; + TypeCode type; + }; + + FullInterfaceDescription describe_interface(); + + // write interface + + AttributeDef create_attribute ( + in RepositoryId id, + in Identifier name, + in VersionSpec version, + in IDLType type, + in AttributeMode mode + ); + + OperationDef create_operation ( + in RepositoryId id, + in Identifier name, + in VersionSpec version, + in IDLType result, + in OperationMode mode, + in ParDescriptionSeq params, + in ExceptionDefSeq exceptions, + in ContextIdSeq contexts + ); + }; + + struct InterfaceDescription { + Identifier name; + RepositoryId id; + RepositoryId defined_in; + VersionSpec version; + RepositoryIdSeq base_interfaces; + }; + + + + enum TCKind { + tk_null, tk_void, + tk_short, tk_long, tk_ushort, tk_ulong, + tk_float, tk_double, tk_boolean, tk_char, + tk_octet, tk_any, tk_TypeCode, tk_Principal, tk_objref, + tk_struct, tk_union, tk_enum, tk_string, + tk_sequence, tk_array, tk_alias, tk_except + }; + + interface TypeCode { // PIDL + exception Bounds {}; + exception BadKind {}; + + // for all TypeCode kinds + boolean equal (in TypeCode tc); + TCKind kind (); + + // for tk_objref, tk_struct, tk_union, tk_enum, tk_alias, and tk_except + RepositoryId id () raises (BadKind); + + // for tk_objref, tk_struct, tk_union, tk_enum, tk_alias, and tk_except + Identifier name () raises (BadKind); + + // for tk_struct, tk_union, tk_enum, and tk_except + unsigned long member_count () raises (BadKind); + Identifier member_name (in unsigned long index) raises (BadKind, Bounds); + + // for tk_struct, tk_union, and tk_except + TypeCode member_type (in unsigned long index) raises (BadKind, Bounds); + + // for tk_union + any member_label (in unsigned long index) raises (BadKind, Bounds); + TypeCode discriminator_type () raises (BadKind); + long default_index () raises (BadKind); + + // for tk_string, tk_sequence, and tk_array + unsigned long length () raises (BadKind); + + // for tk_sequence, tk_array, and tk_alias + TypeCode content_type () raises (BadKind); + + // deprecated interface + long param_count (); + any parameter (in long index) raises (Bounds); + }; + + + /* + * following line added by Christian Blum + */ + interface BOA; + + interface ORB { + // other operations ... + + TypeCode create_struct_tc ( + in RepositoryId id, + in Identifier name, + in StructMemberSeq members + ); + + TypeCode create_union_tc ( + in RepositoryId id, + in Identifier name, + in TypeCode discriminator_type, + in UnionMemberSeq members + ); + + TypeCode create_enum_tc ( + in RepositoryId id, + in Identifier name, + in EnumMemberSeq members + ); + + TypeCode create_alias_tc ( + in RepositoryId id, + in Identifier name, + in TypeCode original_type + ); + + TypeCode create_exception_tc ( + in RepositoryId id, + in Identifier name, + in StructMemberSeq members + ); + + TypeCode create_interface_tc ( + in RepositoryId id, + in Identifier name + ); + + TypeCode create_string_tc ( + in unsigned long bound + ); + + TypeCode create_sequence_tc ( + in unsigned long bound, + in TypeCode element_type + ); + + TypeCode create_recursive_sequence_tc ( + in unsigned long bound, + in unsigned long offset + ); + + TypeCode create_array_tc ( + in unsigned long length, + in TypeCode element_type + ); + + /* + * following line commented out by Christian Blum + */ + // }; + + // The ORB interface (PIDL) is described in Chapter 7, CORBA V2.0 July 1995 + // Object interface (object reference operations): pg 7-3 CORBA V2, 7-95 + // ORB initialization: pg 7-7 CORBA V2, 7-95 + // Object Adapter and Basic Object Adapter initialization: pg 7-8 CORBA V2 7-95 + // Getting initial references: pg 7-10 CORBA V2 7-95 + //PIDL + + /* + * following line commented out by Christian Blum + */ + //interface ORB { + + + string object_to_string (in Object obj); + Object string_to_object (in string str); + + Status create_list ( + in long count, + out NVList new_list + ); + Status create_operation_list ( + in OperationDef oper, + out NVList new_list + ); + Status get_default_context (out Context ctx); + + // Initializing the ORB + typedef string ORBid; + typedef sequence <string> arg_list; + ORB ORB_init (inout arg_list argv, in ORBid orb_identifier); + + // Initializing an object adapter and the Basic Object Adapter + typedef string OAid; + + // Template for OA initialization operations + // <OA> <OA>_init (inout arg_list argv, + // in OAid oa_identifier); + + + + BOA BOA_init (inout arg_list argv, + in OAid boa_identifier); + + + + // Getting initial object references + typedef string ObjectId; + typedef sequence <ObjectId> ObjectIdList; + + exception InvalidName {}; + + ObjectIdList list_initial_services (); + + Object resolve_initial_references (in ObjectId identifier) + raises (InvalidName); + }; + + // had to be changed..., Gerald Brose 1996 + interface ORBject { + + ImplementationDef get_implementation (); + InterfaceDef get_interface (); + boolean is_nil(); + Object duplicate (); + void release (); + boolean is_a (in string logical_type_id); + boolean non_existent(); + boolean is_equivalent (in Object other_object); + unsigned long hash(in unsigned long maximum); + + + Status create_request ( + in Context ctx, + in Identifier operation, + in NVList arg_list, + inout NamedValue result, + out Request request, + in Flags req_flags + ); + }; + + + // Basic Object Adapter interface described in Chapter 8, CORBA V2.0, July 1995 + // interface InterfaceDef; // from Interface Repository // PIDL + // interface ImplementationDef; // from Implementation Repository + // interface Object; // an object reference + // interface Principal; // for the authentication service + typedef sequence <octet, 1024> ReferenceData; + + interface BOA { + Object create ( + in ReferenceData id, + in InterfaceDef intf, + in ImplementationDef impl + ); + void dispose (in Object obj); + ReferenceData get_id (in Object obj); + + void change_implementation (in Object obj, + in ImplementationDef impl + ); + + Principal get_principal (in Object obj, + in Environment ev + ); + + void set_exception (in exception_type major, // NO, USER, + //or SYSTEM_EXCEPTION + in string userid, // exception type id + in any param_LOOK_AT_SOURCE + // in void *param // pointer to associated data + ); + + void impl_is_ready (in ImplementationDef impl); + void deactivate_impl (in ImplementationDef impl); + void obj_is_ready (in Object obj, in ImplementationDef impl); + void deactivate_obj (in Object obj); + }; +}; + +// IOP module described in chap 10 CORBA V2, 7-95 +module IOP{ // IDL + // + // Standard Protocol Profile tag values + // + typedef unsigned long ProfileId; + const ProfileId TAG_INTERNET_IOP = 0; + const ProfileId TAG_MULTIPLE_COMPONENTS = 1; + + struct TaggedProfile { + ProfileId tag; + sequence <octet> profile_data; + }; + + // + // an Interoperable Object Reference is a sequence of + // object-specific protocol profiles, plus a type ID. + // + struct IOR { + string type_id; + sequence <TaggedProfile> profiles; + }; + + // + // Standard way of representing multicomponent profiles. + // This would be encapsulated in a TaggedProfile. + // + typedef unsigned long ComponentId; + struct TaggedComponent { + ComponentId tag; + sequence <octet> component_data; + }; + typedef sequence <TaggedComponent> MultipleComponentProfile; + + + typedef unsigned long ServiceID; + + struct ServiceContext { + ServiceID context_id; + sequence <octet> context_data; + }; + typedef sequence <ServiceContext> ServiceContextList; + + const ServiceID TransactionService = 0; + + + +}; +// GIOP module described in CORBA V2, 7-95 chap 12 +// Complete IDL for GIOP module in CORBA +// V2.0, 7-95 p 10-29 +// GIOP message header: CORBA V2, 7-95 p 12-16 +// GIOP request header: CORBA V2, 7-95 p 12-17 +// GIOP reply header: CORBA V2, 7-95 p 12-19 +// GIOP cancel request and locate request: CORBA V2, 7-95 pp 12-20 -- 12-21 +// GIOP locate reply: CORBA V2, 7-95 p 12-22 +module GIOP { // IDL + enum MsgType { + Request, Reply, CancelRequest, + LocateRequest, LocateReply, + CloseConnection, MessageError + }; + + struct Version { + char major; + char minor; + }; + + struct MessageHeader { + char magic [4]; + Version GIOP_version; + boolean byte_order; + octet message_type; + unsigned long message_size; + }; + + struct RequestHeader { + ::IOP::ServiceContextList service_context; + unsigned long request_id; + boolean response_expected; + sequence <octet> object_key; + string operation; + + /* + * ::CORBA:: added for correct scope + */ + ::CORBA::Principal requesting_principal; + }; + + enum ReplyStatusType { + NO_EXCEPTION, + USER_EXCEPTION, + SYSTEM_EXCEPTION, + LOCATION_FORWARD + }; + + struct ReplyHeader { + ::IOP::ServiceContextList service_context; + unsigned long request_id; + ReplyStatusType reply_status; + }; + + struct CancelRequestHeader { + unsigned long request_id; + }; + + struct LocateRequestHeader { + unsigned long request_id; + sequence <octet> object_key; + }; + + enum LocateStatusType { + UNKNOWN_OBJECT, + OBJECT_HERE, + OBJECT_FORWARD + }; + + struct LocateReplyHeader { + unsigned long request_id; + LocateStatusType locate_status; + }; +}; +// IIOP module described in CORBA V2, 7-95 chap 12 +// Complete IDL for IIOP module: CORBA V2, 7-95 p 12-31 +module IIOP { // IDL + struct Version { + char major; + char minor; + }; + + struct ProfileBody { + Version iiop_version; + string host; + unsigned short port; + sequence <octet> object_key; + }; +}; +// DCE CIOP module described in CORBA V2, 7-95 chap 13 +// IDL for DCE CIOP module: CORBA V2, 7-95 p 13-2 +module DCE_CIOP { + struct InvokeRequestHeader { + boolean byte_order; + ::IOP::ServiceContextList service_context; + sequence <octet> object_key; + string endpoint_id; + string operation; + ::CORBA::Principal principal; + sequence <string> client_context; + + // in and inout parameters follow + }; + enum InvokeResponseStatus { + INVOKE_NO_EXCEPTION, + INVOKE_USER_EXCEPTION, + INVOKE_SYSTEM_EXCEPTION, + INVOKE_LOCATION_FORWARD, + INVOKE_TRY_AGAIN + }; + + struct InvokeResponseHeader { + boolean byte_order; + ::IOP::ServiceContextList service_context; + InvokeResponseStatus status; + + // if status = INVOKE_NO_EXCEPTION, + // result then inouts and outs follow + + // if status = INVOKE_USER_EXCEPTION or + // INVOKE_SYSTEM_EXCEPTION, an exception follows + + // if status = INVOKE_LOCATION_FORWARD, an + // ::IOP::MultipleComponentsProfile follows + }; + + struct LocateRequestHeader { + boolean byte_order; + sequence <octet> object_key; + string endpoint_id; + string operation; + + // no body follows + }; + + module IOP { + + /* + * ::IOP:: added to get the right scope + */ + const ::IOP::ComponentId TAG_OBJECT_KEY = 10; + const ::IOP::ComponentId TAG_ENDPOINT_ID = 11; + const ::IOP::ComponentId TAG_LOCATION_POLICY = 12; + // illegal IDL + /* const octet LOCATE_NEVER = 0; + const octet LOCATE_OBJECT = 1; + const octet LOCATE_OPERATION = 2; + const octet LOCATE_ALWAYS = 3; + */ + }; +}; + +#endif diff --git a/lib/ic/test/ic_SUITE_data/Coss.idl b/lib/ic/test/ic_SUITE_data/Coss.idl new file mode 100644 index 0000000000..c84d4a8247 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/Coss.idl @@ -0,0 +1,1537 @@ +// This file contains OMG IDL and PIDL for the Common Object Services. +// CosNaming Module, p 3-6 CORBAservices, Naming Service V1.0, 3/94 + +// A few minor changes for the JacORB distribution: +// +// added am enclosing COSS module and changed scoped names accordingly +// +// corrected a few syntax errors +// +// commented out: +// #includes +// forward declaration of Object + +#include "Corba.idl" + +module COSS { + +module CosNaming { + + typedef string Istring; + struct NameComponent { + Istring id; + Istring kind; + }; + + typedef sequence <NameComponent> Name; + + enum BindingType {nobject, ncontext}; + + struct Binding { + Name binding_name; + BindingType binding_type; + }; + + typedef sequence <Binding> BindingList; + interface BindingIterator; + + interface NamingContext { + + enum NotFoundReason { missing_node, not_context, not_object}; + + exception NotFound { + NotFoundReason why; + Name rest_of_name; + }; + + exception CannotProceed { + NamingContext cxt; + Name rest_of_name; + }; + + exception InvalidName{}; + exception AlreadyBound {}; + exception NotEmpty{}; + + void bind(in Name n, in Object obj) + raises(NotFound, CannotProceed, InvalidName, AlreadyBound); + void rebind(in Name n, in Object obj) + raises(NotFound, CannotProceed, InvalidName); + void bind_context(in Name n, in NamingContext nc) + raises(NotFound, CannotProceed, InvalidName, AlreadyBound); + void rebind_context(in Name n, in NamingContext nc) + raises(NotFound, CannotProceed, InvalidName); + Object resolve (in Name n) + raises(NotFound, CannotProceed, InvalidName); + void unbind(in Name n) + raises(NotFound, CannotProceed, InvalidName); + NamingContext new_context(); + NamingContext bind_new_context(in Name n) + raises(NotFound, AlreadyBound, CannotProceed, InvalidName); + void destroy( ) + raises(NotEmpty); + void list (in unsigned long how_many, + out BindingList bl, out BindingIterator bi); + }; + + interface BindingIterator { + boolean next_one(out Binding b); + boolean next_n(in unsigned long how_many, + out BindingList bl); + void destroy(); + }; +}; + +// Names Library interface in PIDL, CORBAservices p 3- 14, Naming Service V1.0 3/94 +/* +interface LNameComponent { // PIDL + exception NotSet{}; + string get_id() + raises(NotSet); + void set_id(in string i); + string get_kind() + raises(NotSet); + void set_kind(in string k); + void destroy(); +}; + +interface LName { // PIDL + exception NoComponent{}; + exception OverFlow{}; + exception InvalidName{}; + LName insert_component(in unsigned long i, + in LNameComponent n) + raises(NoComponent, OverFlow); + LNameComponent get_component(in unsigned long i) + raises(NoComponent); + LNameComponent delete_component(in unsigned long i) + raises(NoComponent); + unsigned long num_components(); + boolean equal(in LName ln); + boolean less_than(in LName ln); + Name to_idl_form() + raises(InvalidName); + void from_idl_form(in Name n); + void destroy(); +}; + +LName create_lname(); // C/C++ +LNameComponent create_lname_component(); // C/C++ +*/ + +// CosEventComm Module, CORBAservices p 4-8, Event Service V1.0 3/94 + +module CosEventComm { + + exception Disconnected{}; + + interface PushConsumer { + void push (in any data) raises(Disconnected); + void disconnect_push_consumer(); + }; + + interface PushSupplier { + void disconnect_push_supplier(); + }; + + interface PullSupplier { + any pull () raises(Disconnected); + any try_pull (out boolean has_event) + raises(Disconnected); + void disconnect_pull_supplier(); + }; + + interface PullConsumer { + void disconnect_pull_consumer(); + }; + +}; + +// CosEventChannelAdmin Module, p 4-15 CORBAservices, Event +// Service V1.0, 3/94 + +// #include "CosEventComm.idl" + +module CosEventChannelAdmin { + + exception AlreadyConnected {}; + exception TypeError {}; + + interface ProxyPushConsumer: ::COSS::CosEventComm::PushConsumer { + void connect_push_supplier( + in ::COSS::CosEventComm::PushSupplier push_supplier) + raises(AlreadyConnected); + }; + + interface ProxyPullSupplier: ::COSS::CosEventComm::PullSupplier { + void connect_pull_consumer( + in ::COSS::CosEventComm::PullConsumer pull_consumer) + raises(AlreadyConnected); + }; + + interface ProxyPullConsumer: ::COSS::CosEventComm::PullConsumer { + void connect_pull_supplier( + in ::COSS::CosEventComm::PullSupplier pull_supplier) + raises(AlreadyConnected,TypeError); + }; + + interface ProxyPushSupplier: ::COSS::CosEventComm::PushSupplier { + void connect_push_consumer( + in ::COSS::CosEventComm::PushConsumer + push_consumer) + raises(AlreadyConnected, TypeError); + }; + + + interface ConsumerAdmin { + ProxyPushSupplier obtain_push_supplier(); + ProxyPullSupplier obtain_pull_supplier(); + }; + + interface SupplierAdmin { + ProxyPushConsumer obtain_push_consumer(); + ProxyPullConsumer obtain_pull_consumer(); + }; + + interface EventChannel { + ConsumerAdmin for_consumers(); + SupplierAdmin for_suppliers(); + void destroy(); + }; + +}; + + +// CosTyped Event Module, p 4-22 CORBAservices, Event Service +// V1.0, 3/94 + +// // #include "CosEventComm.idl" + +module CosTypedEventComm { + + interface TypedPushConsumer : ::COSS::CosEventComm::PushConsumer { + Object get_typed_consumer(); + }; + + interface TypedPullSupplier : ::COSS::CosEventComm::PullSupplier { + Object get_typed_supplier(); + }; + +}; + +// CosTypedEventChannelAdmin Module, p 4- 25 CORBAservices, +// Event Service V1.0, 3/94 + +// // #include "CosEventChannel.idl" +// // #include "CosTypedEventComm.idl" +module CosTypedEventChannelAdmin { + exception InterfaceNotSupported {}; + exception NoSuchImplementation {}; + typedef string Key; + + interface TypedProxyPushConsumer : + ::COSS::CosEventChannelAdmin::ProxyPushConsumer, + ::COSS::CosTypedEventComm::TypedPushConsumer { }; + + interface TypedProxyPullSupplier : + ::COSS::CosEventChannelAdmin::ProxyPullSupplier, + ::COSS::CosTypedEventComm::TypedPullSupplier { }; + + interface TypedSupplierAdmin : + ::COSS::CosEventChannelAdmin::SupplierAdmin { + TypedProxyPushConsumer obtain_typed_push_consumer( + in Key supported_interface) + raises(InterfaceNotSupported); + ::COSS::CosEventChannelAdmin::ProxyPullConsumer obtain_typed_pull_consumer ( + in Key uses_interface) + raises(NoSuchImplementation); + }; + + interface TypedConsumerAdmin : + ::COSS::CosEventChannelAdmin::ConsumerAdmin { + TypedProxyPullSupplier obtain_typed_pull_supplier( + in Key supported_interface) + raises (InterfaceNotSupported); + ::COSS::CosEventChannelAdmin::ProxyPushSupplier obtain_typed_push_supplier( + in Key uses_interface) + raises(NoSuchImplementation); + }; + + interface TypedEventChannel { + TypedConsumerAdmin for_consumers(); + TypedSupplierAdmin for_suppliers(); + void destroy (); + }; +}; + + +// CosPersistencePID Module, p 5-20 CORBAservices, +// Persistent Object Service V1.0, 3/94 + +//#ifndef __COSPERSISTENCE +//#define __COSPERSISTENCE + +module CosPersistencePID { + + interface PID { + attribute string datastore_type; + string get_PIDString(); + }; +}; + + +// CosPersistencePDS Module, p 5-20 CORBAservices, +// Persistent Object Service V1.0, 3/94 + +// #include "CosPersistencePID.idl" + +module CosPersistencePDS { + +// interface Object; + interface PDS { + PDS connect (in Object obj, + in ::COSS::CosPersistencePID::PID p); + void disconnect (in Object obj, + in ::COSS::CosPersistencePID::PID p); + void store (in Object obj, + in ::COSS::CosPersistencePID::PID p); + void restore (in Object obj, + in ::COSS::CosPersistencePID::PID p); + void delete (in Object obj, + in ::COSS::CosPersistencePID::PID p); + }; +}; + + +// CosPersistencePO Module, p 5-12 CORBAservices, +// Persistent Object Service V1.0, 3/94 + +// // #include "CosPersistencePDS.idl" +// CosPersistencePDS.idl +// // #includes CosPersistencePID.idl + +module CosPersistencePO { + + interface PO { + attribute ::COSS::CosPersistencePID::PID p; + ::COSS::CosPersistencePDS::PDS connect ( + in ::COSS::CosPersistencePID::PID p); + void disconnect (in ::COSS::CosPersistencePID::PID p); + void store (in ::COSS::CosPersistencePID::PID p); + void restore (in ::COSS::CosPersistencePID::PID p); + void delete (in ::COSS::CosPersistencePID::PID p); + }; + + interface SD { + void pre_store(); + void post_restore(); + }; +}; + + +// CosPersistencePOM Module, p 5-15 CORBAservices, +// Persistent Object Service V1.0, 3/94 + +// #include "CosPersistencePDS.idl" + +// CosPersistencePDS.idl // #includes CosPersistencePID.idl + +module CosPersistencePOM { + +// interface Object; + + interface POM { + ::COSS::CosPersistencePDS::PDS connect ( + in Object obj, + in ::COSS::CosPersistencePID::PID p); + void disconnect ( + in Object obj, + in ::COSS::CosPersistencePID::PID p); + void store ( + in Object obj, + in ::COSS::CosPersistencePID::PID p); + void restore ( + in Object obj, + in ::COSS::CosPersistencePID::PID p); + void delete ( + in Object obj, + in ::COSS::CosPersistencePID::PID p); + }; + }; + +// CosPersistencePDS_DA Module, p 5-22 CORBAservices, +// Persistent Object Service, V1.0, 3/94 + +// #include "CosPersistencePDS.idl" +// CosPersistencePDS.idl // #includes CosPersistencePID.idl + +module CosPersistencePDS_DA { + + typedef string DAObjectID; + + interface PID_DA : ::COSS::CosPersistencePID::PID { + attribute DAObjectID oid; + }; + + interface DAObject { + boolean dado_same(in DAObject d); + DAObjectID dado_oid(); + PID_DA dado_pid(); + void dado_remove(); + void dado_free(); + }; + + interface DAObjectFactory { + DAObject create(); + }; + + interface DAObjectFactoryFinder { + DAObjectFactory find_factory(in string key); + }; + + interface PDS_DA : ::COSS::CosPersistencePDS::PDS { + DAObject get_data(); + void set_data(in DAObject new_data); + DAObject lookup(in DAObjectID id); + PID_DA get_pid(); + PID_DA get_object_pid(in DAObject dao); + DAObjectFactoryFinder data_factories(); + }; + + typedef sequence<string> AttributeNames; + interface DynamicAttributeAccess { + AttributeNames attribute_names(); + any attribute_get(in string name); + void attribute_set(in string name, in any value); + }; + + typedef string ClusterID; + typedef sequence<ClusterID> ClusterIDs; + interface PDS_ClusteredDA : PDS_DA{ + ClusterID cluster_id(); + string cluster_kind(); + ClusterIDs clusters_of(); + PDS_ClusteredDA create_cluster(in string kind); + PDS_ClusteredDA open_cluster(in ClusterID cluster); + PDS_ClusteredDA copy_cluster( + in PDS_DA source); + }; +}; + +// CosPersistenceDDO Module, p 5-32 CORBAservices, Persistent Object Service V1.0, 3/94 + +// #include "CosPersistencePID.idl" +module CosPersistenceDDO { + + interface DDO { + attribute string object_type; + attribute ::COSS::CosPersistencePID::PID p; + short add_data(); + short add_data_property (in short data_id); + short get_data_count(); + short get_data_property_count (in short data_id); + void get_data_property (in short data_id, + in short property_id, + out string property_name, + out any property_value); + void set_data_property (in short data_id, + in short property_id, + in string property_name, + in any property_value); + void get_data (in short data_id, + out string data_name, + out any data_value); + void set_data (in short data_id, + in string data_name, + in any data_value); + }; +}; + +// CosPersistenceDS_CLI module, p 5-34 CORBAservices, +// Persistent Object Service V1.0, 3/94 + +// #include "CosPersistenceDDO.idl" +// CosPersistenceDDO.idl // #includes CosPersistencePID.idl + +module CosPersistenceDS_CLI { + interface UserEnvironment { + void set_option (in long option,in any value); + void get_option (in long option,out any value); + void release(); + }; + + interface Connection { + void set_option (in long option,in any value); + void get_option (in long option,out any value); + }; + + interface ConnectionFactory { + Connection create_object ( + in UserEnvironment user_envir); + }; + + interface Cursor { + void set_position (in long position,in any value); + ::COSS::CosPersistenceDDO::DDO fetch_object(); + }; + + interface CursorFactory { + Cursor create_object ( + in Connection connection); + }; + + interface PID_CLI : ::COSS::CosPersistencePID::PID { + attribute string datastore_id; + attribute string id; + }; + + + + interface Datastore_CLI { + void connect (in Connection connection, + in string datastore_id, + in string user_name, + in string authentication); + void disconnect (in Connection connection); + Connection get_connection ( + in string datastore_id, + in string user_name); + void add_object (in Connection connection, + in ::COSS::CosPersistenceDDO::DDO data_obj); + void delete_object ( + in Connection connection, + in ::COSS::CosPersistenceDDO::DDO data_obj); + void update_object ( + in Connection connection, + in ::COSS::CosPersistenceDDO::DDO data_obj); + void retrieve_object( + in Connection connection, + in ::COSS::CosPersistenceDDO::DDO data_obj); + Cursor select_object( + in Connection connection, + in string key); + void transact (in UserEnvironment user_envir, + in short completion_type); + void assign_PID (in PID_CLI p); + void assign_PID_relative ( + in PID_CLI source_pid, + in PID_CLI target_pid); + boolean is_identical_PID ( + in PID_CLI pid_1, + in PID_CLI pid_2); + string get_object_type (in PID_CLI p); + void register_mapping_schema (in string schema_file); + Cursor execute (in Connection connection, + in string command); + }; + +}; + + +// CosLifeCycle Module, p 6-10 CORBAservices, LifeCycle Service V1.0, 3/94 + +// #include "Naming.idl" + +module CosLifeCycle +{ + typedef ::COSS::CosNaming::Name Key; + typedef Object Factory; + typedef sequence <Factory> Factories; + typedef struct NVP { + ::COSS::CosNaming::Istring name; + any value; + } NameValuePair; + typedef sequence <NameValuePair> Criteria; + + exception NoFactory { + Key search_key; + }; + exception NotCopyable { string reason; }; + exception NotMovable { string reason; }; + exception NotRemovable { string reason; }; + exception InvalidCriteria{ + Criteria invalid_criteria; + }; + exception CannotMeetCriteria { + Criteria unmet_criteria; + }; + + + interface FactoryFinder { + Factories find_factories(in Key factory_key) + raises(NoFactory); + }; + + interface LifeCycleObject { + LifeCycleObject copy(in FactoryFinder there, + in Criteria the_criteria) + raises(NoFactory, NotCopyable, InvalidCriteria, + CannotMeetCriteria); + void move(in FactoryFinder there, + in Criteria the_criteria) + raises(NoFactory, NotMovable, InvalidCriteria, + CannotMeetCriteria); + void remove() + raises(NotRemovable); + }; + + interface GenericFactory { + boolean supports(in Key k); + Object create_object( + in Key k, + in Criteria the_criteria) + raises (NoFactory, InvalidCriteria, + CannotMeetCriteria); + }; +}; + + + +// LifeCycleService Module, p 6- 55 CORBAservices, Life Cycle +// Service V1.0, 3/94 + +// #include "LifeCycle.idl" + +module LifeCycleService { + + typedef sequence <::COSS::CosLifeCycle::NameValuePair> PolicyList; + typedef sequence <::COSS::CosLifeCycle::Key> Keys; + typedef sequence <::COSS::CosLifeCycle::NameValuePair> PropertyList; + typedef sequence <::COSS::CosNaming::NameComponent> NameComponents; + + interface LifeCycleServiceAdmin { + + attribute PolicyList policies; + + void bind_generic_factory( + in ::COSS::CosLifeCycle::GenericFactory gf, + in ::COSS::CosNaming::NameComponent name, + in Keys key_set, + in PropertyList other_properties) + raises (::COSS::CosNaming::NamingContext::AlreadyBound, ::COSS::CosNaming::NamingContext::InvalidName); + + void unbind_generic_factory( + in ::COSS::CosNaming::NameComponent name) + raises (::COSS::CosNaming::NamingContext::NotFound, ::COSS::CosNaming::NamingContext::InvalidName); + + ::COSS::CosLifeCycle::GenericFactory resolve_generic_factory( + in ::COSS::CosNaming::NameComponent name) + raises (::COSS::CosNaming::NamingContext::NotFound, ::COSS::CosNaming::NamingContext::InvalidName); + + NameComponents list_generic_factories(); + + boolean match_service (in ::COSS::CosLifeCycle::GenericFactory f); + + string get_hint(); + + void get_link_properties( + in ::COSS::CosNaming::NameComponent name, + out Keys key_set, + out PropertyList other_properties) + raises (::COSS::CosNaming::NamingContext::NotFound, ::COSS::CosNaming::NamingContext::InvalidName); + }; +}; + +// CosTransactions Module, p 10-66 +// CORBAservices, Transaction Service V1.0, 3/94 + +module CosTransactions { +// DATATYPES +enum Status { + StatusActive, + StatusMarkedRollback, + StatusPrepared, + StatusCommitted, + StatusRolledBack, + StatusUnknown, + StatusNoTransaction +}; + +enum Vote { + VoteCommit, + VoteRollback, + VoteReadOnly +}; + +// Standard exceptions +exception TransactionRequired {}; +exception TransactionRolledBack {}; +exception InvalidTransaction {}; + +// Heuristic exceptions +exception HeuristicRollback {}; +exception HeuristicCommit {}; +exception HeuristicMixed {}; +exception HeuristicHazard {}; + +// Exception from Orb operations +exception WrongTransaction {}; + +// Other transaction-specific exceptions +exception SubtransactionsUnavailable {}; +exception NotSubtransaction {}; +exception Inactive {}; +exception NotPrepared {}; +exception NoTransaction {}; +exception InvalidControl {}; +exception Unavailable {}; + +// Forward references for interfaces defined later in module +interface Control; +interface Terminator; +interface Coordinator; +interface Resource; +interface RecoveryCoordinator; +interface SubtransactionAwareResource; +interface TransactionFactory; +interface TransactionalObject; +interface Current; + +// Current transaction pseudo object (PIDL) + interface Current { + void begin() + raises(SubtransactionsUnavailable); + void commit(in boolean report_heuristics) + raises( + NoTransaction, + HeuristicMixed, + HeuristicHazard + ); + void rollback() + raises(NoTransaction); + void rollback_only() + raises(NoTransaction); + + Status get_status(); + string get_transaction_name(); + void set_timeout(in unsigned long seconds); + + Control get_control(); + Control suspend(); + void resume(in Control which) + raises(InvalidControl); + }; + + interface TransactionFactory { + Control create(in unsigned long time_out); + }; + + interface Control { + Terminator get_terminator() + raises(Unavailable); + Coordinator get_coordinator() + raises(Unavailable); + }; + + interface Terminator { + void commit(in boolean report_heuristics) + raises( + HeuristicMixed, + HeuristicHazard + ); + void rollback(); + }; + + + interface Coordinator { + + Status get_status(); + Status get_parent_status(); + Status get_top_level_status(); + + boolean is_same_transaction(in Coordinator tc); + boolean is_related_transaction(in Coordinator tc); + boolean is_ancestor_transaction(in Coordinator tc); + boolean is_descendant_transaction(in Coordinator tc); + boolean is_top_level_transaction(); + + unsigned long hash_transaction(); + unsigned long hash_top_level_tran(); + + RecoveryCoordinator register_resource(in Resource r) + raises(Inactive); + + void register_subtran_aware(in SubtransactionAwareResource r) + raises(Inactive, NotSubtransaction); + + void rollback_only() + raises(Inactive); + + string get_transaction_name(); + + Control create_subtransaction() + raises(SubtransactionsUnavailable, Inactive); + }; + + interface RecoveryCoordinator { + Status replay_completion(in Resource r) + raises(NotPrepared); + }; + +}; // end module CosTransactions + + +// CosConcurrency Control Module, p 7-8 CORBAservices, +// Concurrency Control Service V1.0, 3/94 + +// #include <CosTransactions.idl> +module CosConcurrencyControl { + + enum lock_mode { + read, + write, + upgrade, + intention_read, + intention_write + }; + + exception LockNotHeld{}; + + interface LockCoordinator + { + void drop_locks(); + }; + + interface LockSet + { + void lock(in lock_mode mode); + boolean try_lock(in lock_mode mode); + + void unlock(in lock_mode mode) + raises(LockNotHeld); + void change_mode(in lock_mode held_mode, + in lock_mode new_mode) + raises(LockNotHeld); + LockCoordinator get_coordinator( + in ::COSS::CosTransactions::Coordinator which); + }; + + interface TransactionalLockSet + { + void lock(in ::COSS::CosTransactions::Coordinator current, + in lock_mode mode); + boolean try_lock(in ::COSS::CosTransactions::Coordinator current, + in lock_mode mode); + void unlock(in ::COSS::CosTransactions::Coordinator current, + in lock_mode mode) + raises(LockNotHeld); + void change_mode(in ::COSS::CosTransactions::Coordinator current, + in lock_mode held_mode, + in lock_mode new_mode) + raises(LockNotHeld); + LockCoordinator get_coordinator( + in ::COSS::CosTransactions::Coordinator which); + }; + + interface LockSetFactory + { + LockSet create(); + LockSet create_related(in LockSet which); + TransactionalLockSet create_transactional(); + TransactionalLockSet create_transactional_related(in + TransactionalLockSet which); + }; +}; + +// CosObjectIdentity Module, p 9-19 CORBAservices, Relationship +// Service V1.0, 3/94 + + +module CosObjectIdentity { + + typedef unsigned long ObjectIdentifier; + + interface IdentifiableObject { + readonly attribute ObjectIdentifier constant_random_id; + boolean is_identical ( + in IdentifiableObject other_object); + }; + +}; + + +// CosRelationships Module, p 9-21 CORBAservices, Relationship +// Service V1.0, 3/94 + +// #include <ObjectIdentity.idl> + +module CosRelationships { + + interface RoleFactory; + interface RelationshipFactory; + interface Relationship; + interface Role; + interface RelationshipIterator; + + typedef Object RelatedObject; + typedef sequence<Role> Roles; + typedef string RoleName; + typedef sequence<RoleName> RoleNames; + + struct NamedRole {RoleName name; Role aRole;}; + typedef sequence<NamedRole> NamedRoles; + + struct RelationshipHandle { + Relationship the_relationship; + ::COSS::CosObjectIdentity::ObjectIdentifier constant_random_id; + }; + typedef sequence<RelationshipHandle> RelationshipHandles; + + interface RelationshipFactory { + struct NamedRoleType { + RoleName name; + ::CORBA::InterfaceDef named_role_type; + }; + typedef sequence<NamedRoleType> NamedRoleTypes; + readonly attribute ::CORBA::InterfaceDef relationship_type; + readonly attribute unsigned short degree; + readonly attribute NamedRoleTypes named_role_types; + exception RoleTypeError {NamedRoles culprits;}; + exception MaxCardinalityExceeded { + NamedRoles culprits;}; + exception DegreeError {unsigned short required_degree;}; + exception DuplicateRoleName {NamedRoles culprits;}; + exception UnknownRoleName {NamedRoles culprits;}; + + Relationship create (in NamedRoles named_roles) + raises (RoleTypeError, + MaxCardinalityExceeded, + DegreeError, + DuplicateRoleName, + UnknownRoleName); + }; + + interface Relationship : + ::COSS::CosObjectIdentity::IdentifiableObject { + exception CannotUnlink { + Roles offending_roles; + }; + readonly attribute NamedRoles named_roles; + void destroy () raises(CannotUnlink); + }; + + interface Role { + exception UnknownRoleName {}; + exception UnknownRelationship {}; + exception RelationshipTypeError {}; + exception CannotDestroyRelationship { + RelationshipHandles offenders; + }; + exception ParticipatingInRelationship { + RelationshipHandles the_relationships; + }; + readonly attribute RelatedObject related_object; + RelatedObject get_other_related_object ( + in RelationshipHandle rel, + in RoleName target_name) + raises (UnknownRoleName, + UnknownRelationship); + Role get_other_role (in RelationshipHandle rel, + in RoleName target_name) + raises (UnknownRoleName, UnknownRelationship); + void get_relationships ( + in unsigned long how_many, + out RelationshipHandles rels, + out RelationshipIterator iterator); + void destroy_relationships() + raises(CannotDestroyRelationship); + void destroy() raises(ParticipatingInRelationship); + boolean check_minimum_cardinality (); + void link (in RelationshipHandle rel, + in NamedRoles named_roles) + raises(RelationshipFactory::MaxCardinalityExceeded, + RelationshipTypeError); + void unlink (in RelationshipHandle rel) + raises (UnknownRelationship); + }; + + interface RoleFactory { + exception NilRelatedObject {}; + exception RelatedObjectTypeError {}; + readonly attribute ::CORBA::InterfaceDef role_type; + readonly attribute unsigned long max_cardinality; + readonly attribute unsigned long min_cardinality; +// the following isn't allowed in IDL, +// readonly attribute sequence <::CORBA::InterfaceDef> related_object_types; + typedef sequence <::CORBA::InterfaceDef> InterfaceDefSeq; + readonly attribute InterfaceDefSeq related_object_types; + Role create_role (in RelatedObject related_object) + raises (NilRelatedObject, RelatedObjectTypeError); + }; + + interface RelationshipIterator { + boolean next_one (out RelationshipHandle rel); + boolean next_n (in unsigned long how_many, + out RelationshipHandles rels); + void destroy (); + }; + +}; + +// CosCompoundExternalization Module, p 8-20 CORBAservices, +// Externalization Service V1.0, 3/94 + +// #include <Graphs.idl> +// #include <Stream.idl> + +// CosGraphs Module, p 9-39 CORBAservices, Relationship Service +// V1.0, 3/94 + +// #include <Relationships.idl> +// #include <ObjectIdentity.idl> + +module CosGraphs { + + interface TraversalFactory; + interface Traversal; + interface TraversalCriteria; + interface Node; + interface NodeFactory; + interface Role; + interface EdgeIterator; + + struct NodeHandle { + Node the_node; + ::COSS::CosObjectIdentity::ObjectIdentifier constant_random_id; + }; + typedef sequence<NodeHandle> NodeHandles; + + struct NamedRole { + Role the_role; + ::COSS::CosRelationships::RoleName the_name; + }; + typedef sequence<NamedRole> NamedRoles; + + struct EndPoint { + NodeHandle the_node; + NamedRole the_role; + }; + typedef sequence<EndPoint> EndPoints; + + struct Edge { + EndPoint from; + ::COSS::CosRelationships::RelationshipHandle the_relationship; + EndPoints relatives; + }; + typedef sequence<Edge> Edges; + + enum PropagationValue {deep, shallow, none, inhibit}; + enum Mode {depthFirst, breadthFirst, bestFirst}; + + interface TraversalFactory { + Traversal create_traversal_on ( + in NodeHandle root_node, + in TraversalCriteria the_criteria, + in Mode how); + }; + + interface Traversal { + typedef unsigned long TraversalScopedId; + struct ScopedEndPoint { + EndPoint point; + TraversalScopedId id; + }; + typedef sequence<ScopedEndPoint> ScopedEndPoints; + struct ScopedRelationship { + ::COSS::CosRelationships::RelationshipHandle + scoped_relationship; + TraversalScopedId id; + }; + struct ScopedEdge { + ScopedEndPoint from; + ScopedRelationship the_relationship; + ScopedEndPoints relatives; + }; + typedef sequence<ScopedEdge> ScopedEdges; + boolean next_one (out ScopedEdge the_edge); + boolean next_n (in short how_many, + out ScopedEdges the_edges); + void destroy (); + }; + + interface TraversalCriteria { + struct WeightedEdge { + Edge the_edge; + unsigned long weight; + sequence<NodeHandle> next_nodes; + }; + typedef sequence<WeightedEdge> WeightedEdges; + void visit_node(in NodeHandle a_node, + in Mode search_mode); + boolean next_one (out WeightedEdge the_edge); + boolean next_n (in short how_many, + out WeightedEdges the_edges); + void destroy(); + }; + + interface Node: ::COSS::CosObjectIdentity::IdentifiableObject { + typedef sequence<Role> Roles; + exception NoSuchRole {}; + exception DuplicateRoleType {}; + + readonly attribute ::COSS::CosRelationships::RelatedObject + related_object; + readonly attribute Roles roles_of_node; + Roles roles_of_type ( + in ::CORBA::InterfaceDef role_type); + void add_role (in Role a_role) + raises (DuplicateRoleType); + void remove_role (in ::CORBA::InterfaceDef of_type) + raises (NoSuchRole); + }; + + interface NodeFactory { + Node create_node (in Object related_object); + }; + + interface Role : ::COSS::CosRelationships::Role { + void get_edges ( in long how_many, + out Edges the_edges, + out EdgeIterator the_rest); + }; + + interface EdgeIterator { + boolean next_one (out Edge the_edge); + boolean next_n ( in unsigned long how_many, + out Edges the_edges); + void destroy (); + }; + +}; + + + +// CosStream Module, 8-15 CORBAservices, +// Externalization Service V1.0, 3/94 + +// #include <LifeCycle.idl> +// #include <ObjectIdentity.idl> +// #include <CompoundExternalization.idl> +module CosStream { + exception ObjectCreationError{}; + exception StreamDataFormatError{}; + interface StreamIO; + + interface Streamable: ::COSS::CosObjectIdentity::IdentifiableObject + { + readonly attribute ::COSS::CosLifeCycle::Key external_form_id; + void externalize_to_stream( + in StreamIO targetStreamIO); + void internalize_from_stream( + in StreamIO sourceStreamIO, + in ::COSS::CosLifeCycle::FactoryFinder there) + raises( ::COSS::CosLifeCycle::NoFactory, + ObjectCreationError, + StreamDataFormatError ); + }; + + interface StreamableFactory { + Streamable create_uninitialized(); + }; + + + interface StreamIO { + void write_string(in string aString); + void write_char(in char aChar); + void write_octet(in octet anOctet); + void write_unsigned_long( + in unsigned long anUnsignedLong); + void write_unsigned_short( + in unsigned short anUnsignedShort); + void write_long(in long aLong); + void write_short(in short aShort); + void write_float(in float aFloat); + void write_double(in double aDouble); + void write_boolean(in boolean aBoolean); + void write_object(in Streamable aStreamable); + // void write_graph(in ::COSS::CosCompoundExternalization::Node aNode); + string read_string() + raises(StreamDataFormatError); + char read_char() + raises(StreamDataFormatError ); + octet read_octet() + raises(StreamDataFormatError ); + unsigned long read_unsigned_long() + raises(StreamDataFormatError ); + unsigned short read_unsigned_short() + raises( StreamDataFormatError ); + long read_long() + raises(StreamDataFormatError ); + short read_short() + raises(StreamDataFormatError ); + float read_float() + raises(StreamDataFormatError ); + double read_double() + raises(StreamDataFormatError ); + boolean read_boolean() + raises(StreamDataFormatError ); + Streamable read_object( + in ::COSS::CosLifeCycle::FactoryFinder there, + in Streamable aStreamable) + raises(StreamDataFormatError ); +// void read_graph( +// in ::COSS::CosCompoundExternalization::Node starting_node, +// in ::COSS::CosLifeCycle::FactoryFinder there) +// raises(StreamDataFormatError ); + }; +}; + +module CosCompoundExternalization { + interface Node; + interface Role; + interface Relationship; + interface PropagationCriteriaFactory; + + struct RelationshipHandle { + Relationship theRelationship; + ::COSS::CosObjectIdentity::ObjectIdentifier constantRandomId; + }; + + interface Node : ::COSS::CosGraphs::Node, ::COSS::CosStream::Streamable{ + void externalize_node (in ::COSS::CosStream::StreamIO sio); + void internalize_node (in ::COSS::CosStream::StreamIO sio, + in ::COSS::CosLifeCycle::FactoryFinder there, + out ::COSS::CosGraphs::Node::Roles rolesOfNode) + raises (::COSS::CosLifeCycle::NoFactory); + }; + + interface Role : ::COSS::CosGraphs::Role { + void externalize_role (in ::COSS::CosStream::StreamIO sio); + void internalize_role (in ::COSS::CosStream::StreamIO sio); + ::COSS::CosGraphs::PropagationValue externalize_propagation ( + in RelationshipHandle rel, + in ::COSS::CosRelationships::RoleName toRoleName, + out boolean sameForAll); + }; + + interface Relationship : + ::COSS::CosRelationships::Relationship { + void externalize_relationship ( + in ::COSS::CosStream::StreamIO sio); + void internalize_relationship( + in ::COSS::CosStream::StreamIO sio, + in ::COSS::CosGraphs::NamedRoles newRoles); + ::COSS::CosGraphs::PropagationValue externalize_propagation ( + in ::COSS::CosRelationships::RoleName fromRoleName, + in ::COSS::CosRelationships::RoleName toRoleName, + out boolean sameForAll); + }; + + interface PropagationCriteriaFactory { + ::COSS::CosGraphs::TraversalCriteria create_for_externalize( ); + }; + +}; + +// CosExternalization Module, 8-12 CORBAservices, +// Externalization Service V1.0, 3/94 + + +// #include <LifeCycle.idl> +// #include <Stream.idl> +module CosExternalization { + exception InvalidFileNameError{}; + exception ContextAlreadyRegistered{}; + interface Stream: ::COSS::CosLifeCycle::LifeCycleObject{ + void externalize( + in ::COSS::CosStream::Streamable theObject); + ::COSS::CosStream::Streamable internalize( + in ::COSS::CosLifeCycle::FactoryFinder there) + raises( ::COSS::CosLifeCycle::NoFactory, + ::COSS::CosStream::StreamDataFormatError ); + void begin_context() + raises( ContextAlreadyRegistered); + void end_context(); + void flush(); + }; + interface StreamFactory { + Stream create(); + }; + interface FileStreamFactory { + Stream create( + in string theFileName) + raises( InvalidFileNameError ); + }; +}; + +// CosContainment Module, p 9- 48 CORBAservices, Relationship +// Service V1.0, 3/94 + +// #include <Graphs.idl> + +module CosContainment { + + interface Relationship : + ::COSS::CosRelationships::Relationship {}; + + interface ContainsRole : ::COSS::CosGraphs::Role {}; + + interface ContainedInRole : ::COSS::CosGraphs::Role {}; + +}; + +// CosExternalizationContainment Module, p 8-26 CORBAservices, +// Externalization Service V1.0, 3/94 + +// #include <Containment.idl> +// #include <CompoundExternalization.idl> + +module CosExternalizationContainment { + + interface Relationship : + ::COSS::CosCompoundExternalization::Relationship, + ::COSS::CosContainment::Relationship {}; + + interface ContainsRole : + ::COSS::CosCompoundExternalization::Role, + ::COSS::CosContainment::ContainsRole {}; + + interface ContainedInRole : + ::COSS::CosCompoundExternalization::Role, + ::COSS::CosContainment::ContainedInRole {}; +}; + +// CosReference Module, p 9-50 CORBAservices, +// Relationship Service V1.0, 3/94 + +// #include <Graphs.idl> + +module CosReference { + + interface Relationship : + ::COSS::CosRelationships::Relationship {}; + + interface ReferencesRole : ::COSS::CosGraphs::Role {}; + + interface ReferencedByRole : ::COSS::CosGraphs::Role {}; + +}; + +// CosExternalizationReference Module, p 8-28 CORBAservices, +// Externalization Service V1.0, 3/94 + +// #include <Reference.idl> +// #include <CompoundExternalization.idl> + +module CosExternalizationReference { + + interface Relationship : + ::COSS::CosCompoundExternalization::Relationship, + ::COSS::CosReference::Relationship {}; + + interface ReferencesRole : + ::COSS::CosCompoundExternalization::Role, + ::COSS::CosReference::ReferencesRole {}; + + interface ReferencedByRole : + ::COSS::CosCompoundExternalization::Role, + ::COSS::CosReference::ReferencedByRole {}; +}; + +// PIDL for CosTSInteroperation Module, p 10-59 +// CORBAservices, Transaction Service V1.0, 3/94 +module CosTSInteroperation { // PIDL + struct otid_t { + long formatID; /*format identifier. 0 is OSI TP */ + long bequal_length; + sequence <octet> tid; + }; + struct TransIdentity { + ::COSS::CosTransactions::Coordinator coordinator; + ::COSS::CosTransactions::Terminator terminator; + otid_t otid; + }; + struct PropagationContext { + unsigned long timeout; + TransIdentity current; + sequence <TransIdentity> parents; + any implementation_specific_data; + }; +}; + +// PIDL for CosTSPortability Module, p 10-63 +// CORBAservices, Transaction Service V1.0, 3/94 + +module CosTSPortability { // PIDL + typedef long ReqId; + + interface Sender { + void sending_request(in ReqId id, + out ::COSS::CosTSInteroperation::PropagationContext ctx); + void received_reply(in ReqId id, + in ::COSS::CosTSInteroperation::PropagationContext ctx, + in ::CORBA::Environment env); + }; + + interface Receiver { + void received_request(in ReqId id, + in ::COSS::CosTSInteroperation::PropagationContext ctx); + void sending_reply(in ReqId id, + out::COSS::CosTSInteroperation::PropagationContext ctx); + }; +}; + +// CosCompoundLifeCycle Module, p 6-30 CORBAservices, +// Life Cycle Service V1.0, 3/94 + +// #include <LifeCycle.idl> +// #include <Relationships.idl> +// #include <Graphs.idl> + +module CosCompoundLifeCycle { + interface OperationsFactory; + interface Operations; + interface Node; + interface Role; + interface Relationship; + interface PropagationCriteriaFactory; + + enum Operation {copy, move, remove}; + + struct RelationshipHandle { + Relationship the_relationship; + ::COSS::CosObjectIdentity::ObjectIdentifier constant_random_id; + }; + + interface OperationsFactory { + Operations create_compound_operations(); + }; + + interface Operations { + Node copy ( + in Node starting_node, + in ::COSS::CosLifeCycle::FactoryFinder there, + in ::COSS::CosLifeCycle::Criteria the_criteria) + raises (::COSS::CosLifeCycle::NoFactory, + ::COSS::CosLifeCycle::NotCopyable, + ::COSS::CosLifeCycle::InvalidCriteria, + ::COSS::CosLifeCycle::CannotMeetCriteria); + void move ( + in Node starting_node, + in ::COSS::CosLifeCycle::FactoryFinder there, + in ::COSS::CosLifeCycle::Criteria the_criteria) + raises (::COSS::CosLifeCycle::NoFactory, + ::COSS::CosLifeCycle::NotMovable, + ::COSS::CosLifeCycle::InvalidCriteria, + ::COSS::CosLifeCycle::CannotMeetCriteria); + void remove (in Node starting_node) + raises (::COSS::CosLifeCycle::NotRemovable); + void destroy(); + }; + + interface Node : ::COSS::CosGraphs::Node { + exception NotLifeCycleObject {}; + void copy_node ( in ::COSS::CosLifeCycle::FactoryFinder there, + in ::COSS::CosLifeCycle::Criteria the_criteria, + out Node new_node, + out ::COSS::CosGraphs::Node::Roles roles_of_new_node) + raises (::COSS::CosLifeCycle::NoFactory, + ::COSS::CosLifeCycle::NotCopyable, + ::COSS::CosLifeCycle::InvalidCriteria, + ::COSS::CosLifeCycle::CannotMeetCriteria); + void move_node (in ::COSS::CosLifeCycle::FactoryFinder there, + in ::COSS::CosLifeCycle::Criteria the_criteria) + raises (::COSS::CosLifeCycle::NoFactory, + ::COSS::CosLifeCycle::NotMovable, + ::COSS::CosLifeCycle::InvalidCriteria, + ::COSS::CosLifeCycle::CannotMeetCriteria); + void remove_node () + raises (::COSS::CosLifeCycle::NotRemovable); + ::COSS::CosLifeCycle::LifeCycleObject get_life_cycle_object() + raises (NotLifeCycleObject); + }; + + interface Role : ::COSS::CosGraphs::Role { + Role copy_role (in ::COSS::CosLifeCycle::FactoryFinder there, + in ::COSS::CosLifeCycle::Criteria the_criteria) + raises (::COSS::CosLifeCycle::NoFactory, + ::COSS::CosLifeCycle::NotCopyable, + ::COSS::CosLifeCycle::InvalidCriteria, + ::COSS::CosLifeCycle::CannotMeetCriteria); + void move_role (in ::COSS::CosLifeCycle::FactoryFinder there, + in ::COSS::CosLifeCycle::Criteria the_criteria) + raises (::COSS::CosLifeCycle::NoFactory, + ::COSS::CosLifeCycle::NotMovable, + ::COSS::CosLifeCycle::InvalidCriteria, + ::COSS::CosLifeCycle::CannotMeetCriteria); + ::COSS::CosGraphs::PropagationValue life_cycle_propagation ( + in Operation op, + in RelationshipHandle rel, + in ::COSS::CosRelationships::RoleName to_role_name, + out boolean same_for_all); + }; + + interface Relationship : + ::COSS::CosRelationships::Relationship { + Relationship copy_relationship ( + in ::COSS::CosLifeCycle::FactoryFinder there, + in ::COSS::CosLifeCycle::Criteria the_criteria, + in ::COSS::CosGraphs::NamedRoles new_roles) + raises (::COSS::CosLifeCycle::NoFactory, + ::COSS::CosLifeCycle::NotCopyable, + ::COSS::CosLifeCycle::InvalidCriteria, + ::COSS::CosLifeCycle::CannotMeetCriteria); + void move_relationship ( + in ::COSS::CosLifeCycle::FactoryFinder there, + in ::COSS::CosLifeCycle::Criteria the_criteria) + raises (::COSS::CosLifeCycle::NoFactory, + ::COSS::CosLifeCycle::NotMovable, + ::COSS::CosLifeCycle::InvalidCriteria, + ::COSS::CosLifeCycle::CannotMeetCriteria); + ::COSS::CosGraphs::PropagationValue life_cycle_propagation ( + in Operation op, + in ::COSS::CosRelationships::RoleName from_role_name, + in ::COSS::CosRelationships::RoleName to_role_name, + out boolean same_for_all); + }; + + interface PropagationCriteriaFactory { + ::COSS::CosGraphs::TraversalCriteria create(in Operation op); + }; + +}; + +// CosLifeCycleContainment Module, p 6-42 CORBAservices, +// Life Cycle Service V1.0, 3/94 + +// #include <Containment.idl> +// #include <CompoundLifeCycle.idl> + +module CosLifeCycleContainment { + + interface Relationship : + ::COSS::CosCompoundLifeCycle::Relationship, + ::COSS::CosContainment::Relationship {}; + + interface ContainsRole : + ::COSS::CosCompoundLifeCycle::Role, + ::COSS::CosContainment::ContainsRole {}; + + interface ContainedInRole : + ::COSS::CosCompoundLifeCycle::Role, + ::COSS::CosContainment::ContainedInRole {}; +}; + +// CosLifeCycleReference Module, p 6-44 CORBAservices, +// Life Cycle Service V1.0, 3/94 + +// #include <Reference.idl> +// #include <CompoundLifeCycle.idl> + +module CosLifeCycleReference { + + interface Relationship : + ::COSS::CosCompoundLifeCycle::Relationship, + ::COSS::CosReference::Relationship {}; + + interface ReferencesRole : + ::COSS::CosCompoundLifeCycle::Role, + ::COSS::CosReference::ReferencesRole {}; + + interface ReferencedByRole : + ::COSS::CosCompoundLifeCycle::Role, + ::COSS::CosReference::ReferencedByRole {}; +}; + + +}; // end module COSS diff --git a/lib/ic/test/ic_SUITE_data/attr.idl b/lib/ic/test/ic_SUITE_data/attr.idl new file mode 100644 index 0000000000..c74223eca6 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/attr.idl @@ -0,0 +1,29 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +interface I1 { + attribute long a1, a2; + attribute char a3; +}; + +interface I2 : I1 { + attribute short a4; + readonly attribute char a5; +}; + diff --git a/lib/ic/test/ic_SUITE_data/c_err1.idl b/lib/ic/test/ic_SUITE_data/c_err1.idl new file mode 100644 index 0000000000..e1bc93dae8 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/c_err1.idl @@ -0,0 +1,63 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// This file forces the bad_tk_match. This triggers when the type of +// the expression does not match the declared type of the constant +// + +const long c1 = TRUE; +const unsigned short c1b= TRUE; +const boolean c2 = +5; +const long c3 = 'c'; +const float c5 = 3; +const unsigned long c6 = -2; // Maybe not checked in compiler or suite + +const boolean c4 = 1 | 2; + + +// Now define some correct constants for use in reference checking + +const long longC = -9; +const short shortC = -9; +const unsigned long ulongC = 1; +const unsigned short ushortC = 0; + +const float floatC = 5.1; +const double doubleC = -2.111; + +const boolean boolC = TRUE; + +const char charC = 'f'; +const string stringC = "hej"; +const string<9> stringCb = "hejdu"; + +// Check the reference errors + +const long c19 = floatC; +const short c20 = doubleC; +const unsigned long c21 = charC; +const unsigned short c22 = stringC; +const float c23 = stringCb; +const double c24 = boolC; +const boolean c25 = longC; +const char c26 = shortC; +const string c27 = ushortC; +const string<9> c28 = ulongC; +const long c29 = 3+floatC; diff --git a/lib/ic/test/ic_SUITE_data/c_err2.idl b/lib/ic/test/ic_SUITE_data/c_err2.idl new file mode 100644 index 0000000000..8dac241c7f --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/c_err2.idl @@ -0,0 +1,30 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// Checks bad type of operands +// + + +const long c1 = 1 + TRUE; +const boolean c3 = TRUE | FALSE | 19.8; +const long c4 = 1 << TRUE; +const long c5 = TRUE >> TRUE; + + diff --git a/lib/ic/test/ic_SUITE_data/c_err3.idl b/lib/ic/test/ic_SUITE_data/c_err3.idl new file mode 100644 index 0000000000..dde9539f6f --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/c_err3.idl @@ -0,0 +1,28 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// Checks ill-formed expressions (type conflict in operands) +// + + +const long c1 = 5|TRUE; +const long c2 = 5&TRUE; +const long c3 = 5^TRUE; + diff --git a/lib/ic/test/ic_SUITE_data/c_norm.idl b/lib/ic/test/ic_SUITE_data/c_norm.idl new file mode 100644 index 0000000000..6f6ef8ff79 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/c_norm.idl @@ -0,0 +1,163 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// Check normal values and expressions for constants +// + +// Integer types +const long co1 = 077; +const long ch1 = 0xf1; +const long ch2 = 0XAB; +const long c1 = 1; +const short c2 = 3; +const unsigned long c3 = 1; +const unsigned short c4 = 3; + +// Unary ops +const long c1hb = -0x1; +const long c1b = -1; +const short c2b = -3; +const long c1c = +1; +const short c2c = +3; +// ~ not supported + +// Check binary ops +const long c1d = 9+1-3; +const long c1hd = 9+1-0xf3; +const short c2d = 7+3; +const short c2e = 7*3; +const long c1e = 1 | 7; +const long c1f = 7 & 9; +const long c1g = (1 | 7) & 9; +const long c1h = 1^7; + +//floats +const float c5 = 1.9; +const double c6 = 1.9; +const float c5b = -1.9; +const double c6b = -1.9; + +// Check type operand casting +const float c5c = 1/(9+2) * 2; +const double c6c = 1.9-1; +//const double c6d = 1; // Does not work yet + +// Booleans and expressions +const boolean c7 = TRUE; +const boolean c7b = FALSE; +const boolean c7c = TRUE | FALSE; +const boolean c7d = TRUE & FALSE; +const boolean c7e = TRUE&TRUE | FALSE&TRUE; +const boolean c7f = TRUE&TRUE ^ FALSE&TRUE; + +// Character and string +const char c8 = 'c'; +const char c8b = '\n'; +const string c9 = "hej"; +const string<9> c9b = "hejdu"; + + +// +// Check that value references work +// + +const long rc1 = c1g; +const long rc1h = c1h + 9; +const short rc2 = c2; +const unsigned long rc3 = c3; +const unsigned short rc4 = c4; + + +const float rc5c = c5c; +const double rc6c = c6c; +const double rc6d = c6c+1.3; + +const boolean rc7 = c7; +const boolean rc7c = c7c | TRUE; + +const char rc8 = c8; +const char rc8b = c8b; +const string rc9 = c9; +const string<9> rc9b = c9b; + + + + +// +// Now check that all typerefs work +// + +typedef long longT; +typedef short shortT; +typedef unsigned long ulongT; +typedef unsigned short ushortT; + +typedef float floatT; +typedef double doubleT; + +typedef char charT; +typedef string stringT; + +typedef boolean booleanT; + +const longT cc1 = 1; +const shortT cc2 = 3; +const ::longT cc1b = -1; +const ::shortT cc2b = -3; + +const floatT cc5 = 1.9; +const doubleT cc6 = 1.9; +const floatT cc5b = -1.9; +const doubleT cc6b = -1.9; +const floatT cc5c = 1/(9+2) * 2; +const doubleT cc6c = 1.9-1; + +const booleanT cc7 = TRUE; +const booleanT cc7b = TRUE; +const booleanT cc7c = TRUE | FALSE; +const booleanT cc7d = TRUE & FALSE; +const booleanT cc7e = TRUE&TRUE | FALSE&TRUE; + + +const charT cc8 = 'c'; +const charT cc8b = '\n'; +const stringT cc9 = "hej"; +const stringT cc9b = "hejdu"; + + +// +// Check value casting +// +const long longC = -9; +const short shortC = -9; +const unsigned long ulongC = 1; +const unsigned short ushortC = 0; + +const float floatC = 5.1; +const double doubleC = -2.111; + +const long c20 = shortC; +const long c21 = ulongC; +const long c22 = ushortC; +const short c23 = ushortC; +const double c34 = floatC; + + + diff --git a/lib/ic/test/ic_SUITE_data/enum.idl b/lib/ic/test/ic_SUITE_data/enum.idl new file mode 100644 index 0000000000..c164e4bf74 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/enum.idl @@ -0,0 +1,32 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + + +enum E1 {kalle, sune}; + +enum E2 { el0, el1, el2, el3, el4, el5, el6, el7, el8, el9, el10, el11, el12, el13, +el14, el15, el16, el17, el18, el19, el20, el21, el22, el23, el24, el25, el26, el27, +el28, el29, el30, el31, el32, el33, el34, el35, el36, el37, el38, el39, el40, el41, +el42, el43, el44, el45, el46, el47, el48, el49, el50, el51, el52, el53, el54, el55, +el56, el57, el58, el59}; + + + + + diff --git a/lib/ic/test/ic_SUITE_data/forward.idl b/lib/ic/test/ic_SUITE_data/forward.idl new file mode 100644 index 0000000000..1e16265af5 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/forward.idl @@ -0,0 +1,34 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// Check that forward declarations are handled correctly +// + + +interface i1; + + +interface i1 { + typedef long T; +}; + + +interface i1; + diff --git a/lib/ic/test/ic_SUITE_data/include.idl b/lib/ic/test/ic_SUITE_data/include.idl new file mode 100644 index 0000000000..24022bfa1e --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/include.idl @@ -0,0 +1,30 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Check that errors are given with the correct file name reference + +#include "include2.idl" + + +typedef T1 T7; +typedef long T7; +typedef long T111; + + + diff --git a/lib/ic/test/ic_SUITE_data/include2.idl b/lib/ic/test/ic_SUITE_data/include2.idl new file mode 100644 index 0000000000..2f8f7fd62c --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/include2.idl @@ -0,0 +1,26 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Check that errors are given with the correct file name reference + +#include "include3.idl" + + +typedef T7 T1; + diff --git a/lib/ic/test/ic_SUITE_data/include3.idl b/lib/ic/test/ic_SUITE_data/include3.idl new file mode 100644 index 0000000000..c5f89c6c63 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/include3.idl @@ -0,0 +1,25 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Check that errors are given with the correct file name reference + +typedef T7 T1; + + + diff --git a/lib/ic/test/ic_SUITE_data/inherit.idl b/lib/ic/test/ic_SUITE_data/inherit.idl new file mode 100644 index 0000000000..71b79c8748 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/inherit.idl @@ -0,0 +1,68 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + + +interface I1 { + typedef long T1; + typedef struct S1 {long a; boolean b;} T2; + typedef string StringT, StringT_arr[10]; + + T1 op1( in StringT a, inout char b, out StringT_arr c ); + T2 op2( in char a, inout char b, out StringT_arr c ); + + const T1 LongC = 10; + const StringT StringC = "Hola bambino"; + +}; + + +interface I2 : I1 { + T1 op3( in long a); + + const long c1 = LongC; + const string c2 = StringC; +}; + +interface I3 : I1 {}; + +interface I4 : I3, I2 {}; // Check that branced inherit works + + + +// Now use cnstants to check that inheritance works as expected + +module m1 { + interface I1 { + typedef long T1; + + const T1 c1 = 9; + }; + + interface I2 : I1 { + const T1 c2 = c1+5; // c2 = 14 + const long c3 = c2+c1+4; // c3 = 27 + }; + + interface I3 : I2, I1 { + const long c1 = 50; // Overrides I1::c1 + const T1 c4 = c1+c2+c3; // c4=91 + const T1 c5 = I1::c1+c1+c2+c3; // 100 + }; +}; + diff --git a/lib/ic/test/ic_SUITE_data/inherit_err.idl b/lib/ic/test/ic_SUITE_data/inherit_err.idl new file mode 100644 index 0000000000..4cfc3ffbff --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/inherit_err.idl @@ -0,0 +1,71 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// Ops and attributes must not be redefined (shadowed) + +interface I1 { + long op1( in long a, inout char b, out boolean c ); + long op2( in char a, inout char b, out boolean c ); + attribute long a1, a2; + readonly attribute char a3; +}; + +interface I2 : I1 { + long op1( in float a, inout char b, out boolean c ); + long op2( in char a, inout char b, out boolean c ); + attribute long a1, a2; + readonly attribute char a3; +}; + +interface I3 : I1 { + long op3 (in string<19> b); +}; + + +interface I4 : I3 { + long op1( in float a, inout char b, out boolean c ); + long op2( in char a, inout char b, out boolean c ); + attribute long a1, a2; + readonly attribute char a3; + + long op3 (in string<19> b); +}; + + +interface I11 { + long op1( in float a, inout char b, out boolean c ); + long op2( in char a, inout char b, out boolean c ); + attribute long a1, a2; + readonly attribute char a3; +}; + + + +interface I5 : I1, I11 {}; + +interface I6 : I1 { + const long op1=0; + const long op2=0; + const long a1=0; + const long a2=0; + const long a3=0; +}; + + diff --git a/lib/ic/test/ic_SUITE_data/inherit_warn.idl b/lib/ic/test/ic_SUITE_data/inherit_warn.idl new file mode 100644 index 0000000000..502bfac8d4 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/inherit_warn.idl @@ -0,0 +1,64 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// Checks that shadow warnings comes out as expected +// + + +interface I1 { + typedef long T1; + typedef struct S1 {long a; boolean b;} T2; + typedef string StringT, StringT_arr[10]; + + T1 op1( in StringT a, inout char b, out StringT_arr c ); + T2 op2( in char a, inout char b, out StringT_arr c ); + + const T1 LongC = 10; + const StringT StringC = "Hola bambino"; + +}; + + +interface I2 : I1 { + typedef char T1; // Shadows I1::T1 + const boolean StringC = FALSE; // shadows I1::StringC + + T1 op3( in long a); + + const long c1 = LongC; + const boolean c2 = StringC; +}; + +interface I3 : I2 {}; // More shadows + +interface I4 : I1 { + T1 op4(); + const T1 c2 = 66; +}; + +interface I5 : I4 { + typedef string T1; // Shadows I1::T1 + const char LongC = 'a'; // Shadows I1::LongC +}; + + +interface I6 : I4, I3 { +}; + diff --git a/lib/ic/test/ic_SUITE_data/mult_ids.idl b/lib/ic/test/ic_SUITE_data/mult_ids.idl new file mode 100644 index 0000000000..46deaa9f55 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/mult_ids.idl @@ -0,0 +1,92 @@ + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// +// Check that multiply defined identifiers are detected +// + +typedef long T1; +typedef long T1; +typedef long T2; +exception T2 {}; + + +//Exceptions +exception Exc1 {}; +exception Exc1 {}; + + +// Enums +enum E1 {kalle}; +enum E1 {kalle}; +enum E2 {kalle, sune, kalle}; + + +// Structs +struct S1 {long a;}; +struct S1 {long a;}; +struct S2 {long a; short a;}; +struct S3 {long a,b; short a;}; +struct S4 {long a,a; short a;}; + + +// Constants +const long c1 = 0; +const long c1 = 0; + + +// Interfaces + +interface i1 {}; +interface i1 {}; + +interface i2 { + attribute long a1; + attribute long a1; +}; + +interface i3 { + attribute long a1, a2; + attribute long a2; +}; + +interface i4 { + attribute long a1, a1; +}; + +interface i5 { + long op1(); + long op1(); + + long op2(in long a, inout char a); +}; + + +// Unions + +union U1 switch (long) {case 1: long a;}; +union U1 switch (long) {case 1: long a;}; + +union U2 switch (long) { +case 1: long a; +default: char a; +}; + + + + + diff --git a/lib/ic/test/ic_SUITE_data/nasty.idl b/lib/ic/test/ic_SUITE_data/nasty.idl new file mode 100644 index 0000000000..15fd523c0f --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/nasty.idl @@ -0,0 +1,60 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// Checks nasty name collisions +// + +typedef string T; + + +#define nasty01 version +#define nasty02 preproc +#define nasty03 pragma +#define nasty04 compile +#define nasty05 if +#define nasty06 receive +#define nasty07 foldr +#define nasty08 length +#define nasty09 ID + +interface I1 { + attribute T nasty01; + attribute T nasty02; + attribute T nasty03; + attribute T nasty04; + attribute T nasty05; + attribute T nasty06; + attribute T nasty07; + attribute T nasty08; + attribute T nasty09; +}; + +interface I2 { + T nasty01(); + T nasty02(); + T nasty03(); + T nasty04(); + T nasty05(); + T nasty06(); + T nasty07(); + T nasty08(); + T nasty09(); +}; + diff --git a/lib/ic/test/ic_SUITE_data/one.idl b/lib/ic/test/ic_SUITE_data/one.idl new file mode 100644 index 0000000000..99281d6079 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/one.idl @@ -0,0 +1,29 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Test oneway operations + +interface I1 { + long op1(in char a, inout boolean b, out string c); + oneway void op2(in char a, in boolean b, in string c); + oneway void op3(); +}; + + + diff --git a/lib/ic/test/ic_SUITE_data/one_followed.idl b/lib/ic/test/ic_SUITE_data/one_followed.idl new file mode 100644 index 0000000000..da8ee74e25 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/one_followed.idl @@ -0,0 +1,54 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Test oneway operations followed by other operations + +interface I1 { + oneway void op1(); + oneway void op2(in char a, in boolean b, in string c); + long op3(in char a, inout boolean b, out string c); +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/ic/test/ic_SUITE_data/one_out.idl b/lib/ic/test/ic_SUITE_data/one_out.idl new file mode 100644 index 0000000000..65f177ff22 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/one_out.idl @@ -0,0 +1,28 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Test oneway operations not using in out params + +interface I1 { + oneway void op1(in char a, inout boolean b, in string c); + oneway void op2(in char a, out boolean b, in string c); +}; + + + diff --git a/lib/ic/test/ic_SUITE_data/one_raises.idl b/lib/ic/test/ic_SUITE_data/one_raises.idl new file mode 100644 index 0000000000..8290877363 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/one_raises.idl @@ -0,0 +1,32 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Test oneway operations not using in out params + +exception hell {boolean burn; unsigned long for_how_long;}; +exception high_water {long mark;}; + +interface I1 { + oneway void op1(in char a) raises (hell); + oneway void op2(in char a) raises (hell); + oneway void op3() raises (hell, high_water); +}; + + + diff --git a/lib/ic/test/ic_SUITE_data/one_void.idl b/lib/ic/test/ic_SUITE_data/one_void.idl new file mode 100644 index 0000000000..e1d51c7abb --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/one_void.idl @@ -0,0 +1,30 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Test oneway operations not using in out params + +typedef long T; + +interface I1 { + oneway char op1(in char a); + oneway T op2(in char a); +}; + + + diff --git a/lib/ic/test/ic_SUITE_data/raises_reg.idl b/lib/ic/test/ic_SUITE_data/raises_reg.idl new file mode 100644 index 0000000000..d4458811dc --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/raises_reg.idl @@ -0,0 +1,52 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#ifndef _RAISES_REG_IDL +#define _RAISES_REG_IDL + +module Raises_RegModule { + + exception Exception_1 {}; + + exception Exception_2 {}; + + interface R_R { + + void op() + raises(Raises_RegModule::Exception_1,Raises_RegModule::Exception_2); + + }; + +}; + +#endif + + + + + + + + + + + + + + + diff --git a/lib/ic/test/ic_SUITE_data/struct.idl b/lib/ic/test/ic_SUITE_data/struct.idl new file mode 100644 index 0000000000..337ee170e3 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/struct.idl @@ -0,0 +1,53 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + + +struct S1 { + long a; + char b; + string<9> s; +}; + +struct S2 { + long a; + struct S3 { + long a; + short b, b1; + char c; + } b; + sequence <S1> c, c2, c3, c4, c5, c6, c7; +}; + + +// Check that structs are detected down in other types + + +typedef struct s4 {long a;} T1; +union U1 switch (long) { +case 1: + struct S5 {unsigned short a;} a; +case 2: + union U2 switch (char) { + case 'a': + boolean a; + case 'b': + struct s6 {long a; boolean b;} c; + } b; +}; + diff --git a/lib/ic/test/ic_SUITE_data/syntax1.idl b/lib/ic/test/ic_SUITE_data/syntax1.idl new file mode 100644 index 0000000000..83c7de7943 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/syntax1.idl @@ -0,0 +1,28 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// Check syntax errors +// + + +typedef long T1 _; + + + diff --git a/lib/ic/test/ic_SUITE_data/syntax2.idl b/lib/ic/test/ic_SUITE_data/syntax2.idl new file mode 100644 index 0000000000..10498206c1 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/syntax2.idl @@ -0,0 +1,27 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +struct S2 { + long a_arr[99]; + struct S3 { + long a;_arr[99] + boolean b_arr[99]; + } b; +}; + + diff --git a/lib/ic/test/ic_SUITE_data/syntax3.idl b/lib/ic/test/ic_SUITE_data/syntax3.idl new file mode 100644 index 0000000000..69ab6b9783 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/syntax3.idl @@ -0,0 +1,20 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +typdef long T1; + diff --git a/lib/ic/test/ic_SUITE_data/syntax4.idl b/lib/ic/test/ic_SUITE_data/syntax4.idl new file mode 100644 index 0000000000..077a251729 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/syntax4.idl @@ -0,0 +1,23 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +union U1 switch (long) { +case 1: long a; +2: short b; +}; + diff --git a/lib/ic/test/ic_SUITE_data/syntax5.idl b/lib/ic/test/ic_SUITE_data/syntax5.idl new file mode 100644 index 0000000000..10af9fc18c --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/syntax5.idl @@ -0,0 +1,22 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +union U1 switch (enum E1 {kalle, sune}) { +case kalle: long a; +sune: short b; +}; diff --git a/lib/ic/test/ic_SUITE_data/syntax6.idl b/lib/ic/test/ic_SUITE_data/syntax6.idl new file mode 100644 index 0000000000..dc15704d94 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/syntax6.idl @@ -0,0 +1,20 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +constant long c1 = 0; diff --git a/lib/ic/test/ic_SUITE_data/type.idl b/lib/ic/test/ic_SUITE_data/type.idl new file mode 100644 index 0000000000..67e1d502bd --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/type.idl @@ -0,0 +1,190 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// Check all types in IDL +// + +typedef long T01; +typedef unsigned long T02; +typedef short T03; +typedef unsigned short T04; +typedef float T05; +typedef double T06; +typedef char T07; +typedef boolean T08; +typedef octet T09; +typedef any T10; +typedef Object T11; +typedef T01 T12; + +// Template types +typedef sequence <long> T21; +typedef sequence <unsigned long> T22; +typedef sequence <short, 2> T23; +typedef sequence <unsigned short, 6> T24; +typedef sequence <float, 12> T25; +typedef sequence <double> T26; +typedef sequence <char, 1> T27; +typedef sequence <boolean> T28; +typedef sequence <octet, 9> T29; +typedef sequence <any> T30; +typedef sequence <Object,2 > T31; +typedef sequence <T01> T32; +typedef sequence <sequence <sequence <T32> > > T33; + +struct S1 { + long a; + boolean b; +}; + +struct S2 { + long a; + struct S3 { + long a; + boolean b; + } b; +}; + +union U1 switch (enum E1 {kalle1, sune1}) { +case kalle1: long a; +default: boolean b; +case sune1: octet c; +}; + +union U2 switch (enum E2 {kalle2, sune2}) { +case kalle2: long a; +default: struct S4 { long a; short b;} b; +case sune2: octet c; +}; + +// Typedefs of above types + +typedef struct S11 { + long a; + boolean b; +} T41; + +typedef struct S21 { + long a; + struct S3 { + long a; + boolean b; + } b; +} T42; + +typedef union U11 switch (enum E3 {kalle3, sune3}) { +case kalle3: long a; +default: boolean b; +case sune3: octet c; +} T43; + +typedef union U21 switch (enum E4 {kalle4, sune4}) { +case kalle4: long a; +default: struct S4 { long a; short b;} b; +case sune4: octet c; +} T44; + + + + +// Array versions + +typedef long T01_arr[99]; +typedef unsigned long T02_arr[99]; +typedef short T03_arr[99]; +typedef unsigned short T04_arr[99]; +typedef float T05_arr[99]; +typedef double T06_arr[99]; +typedef char T07_arr[99]; +typedef boolean T08_arr[99]; +typedef octet T09_arr[99]; +typedef any T10_arr[99]; +typedef Object T11_arr[99]; +typedef T01 T12_arr[99]; + +typedef sequence <long> T21_arr[99]; +typedef sequence <unsigned long> T22_arr[99]; +typedef sequence <short, 2> T23_arr[99]; +typedef sequence <unsigned short, 6> T24_arr[99]; +typedef sequence <float, 12> T25_arr[99]; +typedef sequence <double> T26_arr[99]; +typedef sequence <char, 1> T27_arr[99]; +typedef sequence <boolean> T28_arr[99]; +typedef sequence <octet, 9> T29_arr[99]; +typedef sequence <any> T30_arr[99]; +typedef sequence <Object,2 > T31_arr[99]; +typedef sequence <T01> T32_arr[99]; +typedef sequence <sequence <sequence <T32> > > T33_arr[99]; + +struct S12 { + long a; + boolean b_arr[99]; +}; + +struct S22 { + long a_arr[99]; + struct S3 { + long a_arr[99]; + boolean b_arr[99]; + } b; +}; + +union U12 switch (enum E12 {kalle12, sune12}) { +case kalle12: long a_arr[99]; +default: boolean b; +case sune12: octet c; +}; + +union U22 switch (enum E22 {kalle22, sune22}) { +case kalle22: long a; +default: struct S4 { long a; short b;} b_arr[99]; +case sune22: octet c; +}; + +// Typedefs of above types + +typedef struct S13 { + long a_arr[99]; + boolean b; +} T41_arr[99]; + +typedef struct S23 { + long a; + struct S3 { + long a; + boolean b_arr[99]; + char c; + } b; +} T42_arr[99]; + +typedef union U13 switch (enum E13 {kalle13, sune13}) { +case kalle13: long a; +default: boolean b_arr[99]; +case sune13: octet c; +} T43_arr[99]; + +typedef union U23 switch (enum E23 {kalle23, sune23}) { +case kalle23: long a_arr[99]; +default: struct S4 { long a; short b;} b_arr[99]; +case sune23: octet c_arr[99]; +} T44_arr[99]; + + + diff --git a/lib/ic/test/ic_SUITE_data/typeid.idl b/lib/ic/test/ic_SUITE_data/typeid.idl new file mode 100644 index 0000000000..6e99f4a50d --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/typeid.idl @@ -0,0 +1,28 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +interface I1 {}; + +module M1 { interface I1 {};}; + +module M2 { module M1 { interface I1 {};};}; + +module M3 { module M2 { module M1 { interface I1 {};};};}; + + diff --git a/lib/ic/test/ic_SUITE_data/u_case_mult.idl b/lib/ic/test/ic_SUITE_data/u_case_mult.idl new file mode 100644 index 0000000000..3c30e144d8 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/u_case_mult.idl @@ -0,0 +1,54 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Check that case labels are not duplicated + +union U1 switch (long) { +case 1 : long a; +case 1 : short b; +}; + +union U2 switch (char) { +case 'c' : long a; +case 'c' : short b; +}; + +union U2b switch (char) { +case 'c' : +case 'c' : long a; +case 'e': long b; +case 'c': long c; +}; + +union U3 switch (enum E1 {kalle, kula}) { +case kula : long a; +case kula : short b; +}; + +union U4 switch (boolean) { +case TRUE : long a; +case TRUE : short b; +}; + +union U5 switch (boolean) { +case TRUE : long a; +default: short p; +default: short pp; +}; + diff --git a/lib/ic/test/ic_SUITE_data/u_default.idl b/lib/ic/test/ic_SUITE_data/u_default.idl new file mode 100644 index 0000000000..e5d94a5e54 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/u_default.idl @@ -0,0 +1,51 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// Checking that default labels are correct in TK +// + +interface i1 { + union U1 switch (long) { + default: long a; + case 1: case 2: long b; + }; + + union U2 switch (long) { + case 0: default: long a; + case 1: case 2: long b; + }; + + union U3 switch (long) { + case -1: long aa; + case 0: default: long a; + case 1: case 2: long b; + }; + + union U4 switch (long) { + case -1: long aa; + case 0: long a; + case 1: case 2: long b; + }; + + U1 op0(); + U2 op1(); + U3 op2(); + U4 op3(); +}; diff --git a/lib/ic/test/ic_SUITE_data/u_mult.idl b/lib/ic/test/ic_SUITE_data/u_mult.idl new file mode 100644 index 0000000000..b916861eec --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/u_mult.idl @@ -0,0 +1,61 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + + +// Check multiply defined declarators + +enum E2 {kal, kula, E1}; // legal, but used below + +// Now check that declarator a is multiply defined in all unions below +union U0 switch (long) { +case 0: long a; +case 1: short a; +}; +union U00 switch (char) { +case 'c' : long a; +case 'f' : char c; +case 'b' : short a; +}; +union U000 switch (boolean) { +case TRUE: long a; +case FALSE: short a; +}; +union U0000 switch (E2) { +case kal: long a; +case kula: short a; +}; + + + + +// Check that enum name duplication is found. + +union U1 switch (enum E1 {kalle, kula, E1}) { +case E1 : long a; // legal +case kalle : short E1; // illegal +}; + + +// This is legal, but ended up here anyway + +union U2 switch(::E2) { +case kal : long a; +case kula : short b; +default : boolean E1; +}; diff --git a/lib/ic/test/ic_SUITE_data/u_norm.idl b/lib/ic/test/ic_SUITE_data/u_norm.idl new file mode 100644 index 0000000000..e23796b8ca --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/u_norm.idl @@ -0,0 +1,63 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + + +union U1 switch (long) { +case 1: long a; +case 2: case 3: short b; +}; + + +union U2 switch (unsigned short) { +case 10: boolean a; +case 188: char b; +default: string c; +}; + + +union U3 switch (enum E1 {kalle, kula, boll}) { +case kalle: long a; +case kula: U2 b; +}; + +enum E2 {Cissi, Anders}; + +union U4 switch (::E2) { +case Cissi: U1 a; +default: case Anders: unsigned long b; +}; + +union U5 switch(char) { +case 'e': long a; +case 'b': case 'f': char b; +default: struct S {long a; boolean b;} c; +}; + + +// Now check that references can be used as case values + +const long c1 = 9; +const long c2 = 10; + +union U6 switch (long) { +case c1: boolean a; +case ::c2: boolean b; +}; + + diff --git a/lib/ic/test/ic_SUITE_data/u_type.idl b/lib/ic/test/ic_SUITE_data/u_type.idl new file mode 100644 index 0000000000..44e3326305 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/u_type.idl @@ -0,0 +1,82 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + + +// +// Check that case values match declared discriminator type +// + + +const long longC = 0; +const short shortC = 0; +const char charC = 'c'; +const string stringC = "Yacht"; + +enum E1 {kalle, kula}; + +union U1 switch (long) { +case 'c' : long a; +case TRUE : long b; +case stringC : long d; +case kalle : long f; +}; + +union U2 switch (unsigned long) { +case 'c' : long a; +case TRUE : long b; +case stringC : long d; +case kalle : long f; +}; + +union U3 switch (short) { +case 'c' : long a; +case TRUE : long b; +case stringC : long d; +case kalle : long f; +}; + +union U4 switch (unsigned short) { +case 'c' : long a; +case TRUE : long b; +case stringC : long d; +case kalle : long f; +}; + +union U5 switch (char) { +case TRUE : long b; +case stringC : long d; +case shortC : long e; +case kalle : long f; +}; + + +union U6 switch (E1) { +case 'c' : long a; +case TRUE : long b; +case stringC : long d; +case shortC : long e; +}; + +union U7 switch (enum E2 {ja, nej, kanske}) { +case 'c' : long a; +case TRUE : long b; +case stringC : long d; +case shortC : long e; +}; + diff --git a/lib/ic/test/ic_SUITE_data/undef_id.idl b/lib/ic/test/ic_SUITE_data/undef_id.idl new file mode 100644 index 0000000000..01a35c4ef8 --- /dev/null +++ b/lib/ic/test/ic_SUITE_data/undef_id.idl @@ -0,0 +1,63 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1997-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// +// Check that undefined ids are detected +// + +typedef T7 T1; + +const char c1 = ::c0; +const T01 c2 = 'h'; +const T7 c3 = 9; + +interface i1 { + T17 op(); + long op2( in T7 a); + attribute T7 a1, a2; + readonly attribute T17 a3; +}; + +union U1 switch (long) { +case 1: long a; +case ::g : short b; +}; + +union U2 switch (enum E1 {kalle, kula}) { +case kula1: long a; +case kalle : short b; +}; + +union U3 switch (long) { +case kula2: long a; +case ::E3::kalle : short b; +case ::E4::kalle : short c; +}; + +enum E2 {kalle2, kula2}; + +union U4 switch (E2) { +case kula1: long a; +case kula1: long b; +case c3: short c; +}; + + + + diff --git a/lib/ic/test/ic_be_SUITE.erl b/lib/ic/test/ic_be_SUITE.erl new file mode 100644 index 0000000000..e3caf7bdff --- /dev/null +++ b/lib/ic/test/ic_be_SUITE.erl @@ -0,0 +1,69 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%%---------------------------------------------------------------------- +%%% Purpose : Test suite for the backends of the IDL compiler +%%%---------------------------------------------------------------------- + +-module(ic_be_SUITE). +-include("test_server.hrl"). + + +-export([all/1,plain/1]). + + +-define(OUT(X), filename:join([?config(priv_dir, Config), gen, to_list(X)])). + + +%% Top of cases + +all(suite) -> [plain]. + + + +plain(doc) -> + ["Checking code for the plain backend."]; +plain(suite) -> []; +plain(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(slask), + File = filename:join(DataDir, plain), + + ?line ok = ic:gen(File,stdopts(OutDir)++[{be,erl_plain}]), + + ok. + + + + +%%-------------------------------------------------------------------- +%% +%% Utilities + + +stdopts(OutDir) -> + [{outdir, OutDir}, {maxerrs, infinity}]. + + + + + +to_list(X) when is_atom(X) -> atom_to_list(X); +to_list(X) -> X. + diff --git a/lib/ic/test/ic_be_SUITE_data/plain.idl b/lib/ic/test/ic_be_SUITE_data/plain.idl new file mode 100644 index 0000000000..ee0a995807 --- /dev/null +++ b/lib/ic/test/ic_be_SUITE_data/plain.idl @@ -0,0 +1,33 @@ + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +module m { + + struct s { + long x; + long y; + }; + + interface i { + + void foo( in s a, out short b ); + + }; + +}; + diff --git a/lib/ic/test/ic_pp_SUITE.erl b/lib/ic/test/ic_pp_SUITE.erl new file mode 100644 index 0000000000..d68242bf3a --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE.erl @@ -0,0 +1,647 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose : Test suite for the IDL preprocessor +%%---------------------------------------------------------------------- + +-module(ic_pp_SUITE). +-include("test_server.hrl"). + + + +%% Standard options to the ic compiler, NOTE unholy use of OutDir + +-define(OUT(X), filename:join([?config(priv_dir, Config), gen, to_list(X)])). +-define(GCC, "g++"). +-define(GCC_VER, "2.95.3"). + +-export([all/1]). +-export([arg/1]). +-export([arg_norm/1]). +-export([cascade/1]). +-export([cascade_norm/1]). +-export([comment/1]). +-export([comment_norm/1]). +-export([concat/1]). +-export([concat_norm/1]). +-export([define/1]). +-export([define_norm/1]). +-export(['if'/1]). +-export([if_norm/1]). +-export([if_zero/1]). +-export([misc/1]). +-export([misc_norm/1]). +-export([improp_nest_constr/1]). +-export([improp_nest_constr_norm/1]). +-export([inc/1]). +-export([inc_norm/1]). +-export([line/1]). +-export([line_norm/1]). +-export([nopara/1]). +-export([nopara_norm/1]). +-export([predef/1]). +-export([predef_norm/1]). +-export([predef_time/1]). +-export([predef_time_norm/1]). +-export([self_ref/1]). +-export([self_ref_norm/1]). +-export([separate/1]). +-export([separate_norm/1]). +-export([swallow_sc/1]). +-export([swallow_sc_norm/1]). +-export([unintended_grp/1]). +-export([unintended_grp_norm/1]). +-export([cases/0, init_all/1, finish_all/1]). + + +all(doc) -> ["Preprocessing tests for IC"]; +all(suite) -> + {req, [], {conf, init_all, cases(), finish_all}}. + +init_all(Config) -> + if + is_list(Config) -> + case os:type() of + {win32, _} -> + {skipped, "Very unplesent to run on windows"}; + _ -> + check_gcc(Config) + end; + true -> + exit("Config not a list") + end. + +check_gcc(Config) -> + case os:find_executable(?GCC) of + false -> + {skipped, + lists:flatten(io_lib:format("Can not run without ~s in path", + [?GCC]))}; + _ -> + case trim(os:cmd(?GCC++" --version")) of + ?GCC_VER++[] -> + Config; + ?GCC_VER++[D|_] when is_integer(D), D>=$0, D=<$9 -> + fail_gcc(?GCC_VER++[D]); + ?GCC_VER++_ -> + Config; + Ver -> + fail_gcc(Ver) + end + end. + +fail_gcc(Ver) -> + {skipped, lists:flatten(io_lib:format("Need ~s v~s, not ~s", + [?GCC, ?GCC_VER, Ver]))}. + +trim(S) -> lists:reverse(skip_white(lists:reverse(skip_white(S)))). + +skip_white([$\s|T]) -> skip_white(T); +skip_white([$\n|T]) -> skip_white(T); +skip_white([$\r|T]) -> skip_white(T); +skip_white([$\t|T]) -> skip_white(T); +skip_white(L) -> L. + + +finish_all(Config) -> + Config. + + +cases() -> + [arg, cascade, comment, concat, define, misc, 'if', improp_nest_constr, inc, + line, nopara, predef, predef_time, self_ref, separate, swallow_sc, + unintended_grp]. + + + +%%-------------------------------------------------------------------- +%% arg +%%-------------------------------------------------------------------- + +arg(suite) -> [arg_norm]; +arg(doc) -> ["Check #define with some arguments"]. + +arg_norm(doc) -> ["Checks arguments for #define."]; +arg_norm(suite) -> []; +arg_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(arg_norm), + File = filename:join(DataDir, arg), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% cascade +%%-------------------------------------------------------------------- + +cascade(suite) -> [cascade_norm]; +cascade(doc) -> ["Check cascade #define"]. + +cascade_norm(doc) -> ["Check cascade #define."]; +cascade_norm(suite) -> []; +cascade_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(cascade_norm), + File = filename:join(DataDir, cascade), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% comment +%%-------------------------------------------------------------------- + +comment(suite) -> [comment_norm]; +comment(doc) -> ["Check comments"]. + +comment_norm(doc) -> ["Check comments."]; +comment_norm(suite) -> []; +comment_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(comment_norm), + File = filename:join(DataDir, comment), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% concat +%%-------------------------------------------------------------------- + +concat(suite) -> [concat_norm]; +concat(doc) -> ["Check concatinations, i.e ## "]. + +concat_norm(doc) -> ["Check concatinations, i.e ## ."]; +concat_norm(suite) -> []; +concat_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(concat_norm), + File = filename:join(DataDir, concat), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% define +%%-------------------------------------------------------------------- + +define(suite) -> [define_norm]; +define(doc) -> ["Check misceleaneous #define"]. + +define_norm(doc) -> ["Check misceleaneous #define."]; +define_norm(suite) -> []; +define_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(define_norm), + File = filename:join(DataDir, define), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% if +%%-------------------------------------------------------------------- + +'if'(suite) -> [if_norm, if_zero]; +'if'(doc) -> ["Check #if, #elif, and #endif. Note these are not implementen and will ~n + result in an error message from internal_pp"]. + +if_norm(doc) -> ["Check #if, #elif, and #endif. ."]; +if_norm(suite) -> []; +if_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(if_norm), + File = filename:join(DataDir, 'if'), + + ?line ok = test_file(File, DataDir), + ok. + +if_zero(doc) -> ["Check #if 0"]; +if_zero(suite) -> []; +if_zero(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(if_zero), + File = filename:join(DataDir, if_zero), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% inc +%%-------------------------------------------------------------------- + +inc(suite) -> [inc_norm]; +inc(doc) -> ["Check #include"]. + +inc_norm(doc) -> ["Check #include."]; +inc_norm(suite) -> []; +inc_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(inc_norm), + File = filename:join(DataDir, inc), + + ?line ok = test_file(File, DataDir), + ok. + + + +%%-------------------------------------------------------------------- +%% improp_nest_constr +%%-------------------------------------------------------------------- + +improp_nest_constr(suite) -> [improp_nest_constr_norm]; +improp_nest_constr(doc) -> ["Check improperly nested constructs"]. + +improp_nest_constr_norm(doc) -> ["Check improperly nested constructs."]; +improp_nest_constr_norm(suite) -> []; +improp_nest_constr_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(improp_nest_constr_norm), + File = filename:join(DataDir, improp_nest_constr), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% misc +%%-------------------------------------------------------------------- + +misc(suite) -> [misc_norm]; +misc(doc) -> ["Misceleaneous checks"]. + +misc_norm(doc) -> ["Misceleaneous checks."]; +misc_norm(suite) -> []; +misc_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(misc_norm), + File = filename:join(DataDir, misc), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% line +%%-------------------------------------------------------------------- + +line(suite) -> [line_norm]; +line(doc) -> ["Checks #line"]. + +line_norm(doc) -> ["Checks #line."]; +line_norm(suite) -> []; +line_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(line_norm), + File = filename:join(DataDir, line), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% nopara +%%-------------------------------------------------------------------- + +nopara(suite) -> [nopara_norm]; +nopara(doc) -> ["Checks #define with no parameters"]. + +nopara_norm(doc) -> ["Checks #define with no parameters."]; +nopara_norm(suite) -> []; +nopara_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(nopara_norm), + File = filename:join(DataDir, nopara), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% predef +%%-------------------------------------------------------------------- + +predef(suite) -> [predef_norm]; +predef(doc) -> ["Checks predefined macros. Note: not __TIME__ and __DATE__"]. + +predef_norm(doc) -> ["Checks predefined macros. Note: not __TIME__ and __DATE__."]; +predef_norm(suite) -> []; +predef_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(predef_norm), + File = filename:join(DataDir, predef), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% predef_time +%%-------------------------------------------------------------------- + +predef_time(suite) -> [predef_time_norm]; +predef_time(doc) -> ["Checks the predefined macros __TIME__ and __DATE__"]. + +predef_time_norm(doc) -> ["Checks the predefined macros __TIME__ and __DATE__."]; +predef_time_norm(suite) -> []; +predef_time_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(predef_time_norm), + File = filename:join(DataDir, predef_time), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% self_ref +%%-------------------------------------------------------------------- + +self_ref(suite) -> [self_ref_norm]; +self_ref(doc) -> ["Checks self referring macros"]. + +self_ref_norm(doc) -> ["Checks self referring macros."]; +self_ref_norm(suite) -> []; +self_ref_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(self_ref_norm), + File = filename:join(DataDir, self_ref), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% separate +%%-------------------------------------------------------------------- + +separate(suite) -> [separate_norm]; +separate(doc) -> ["Checks separete expansion of macro arguments"]. + +separate_norm(doc) -> ["Checks separete expansion of macro arguments."]; +separate_norm(suite) -> []; +separate_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(separate_norm), + File = filename:join(DataDir, separate), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% swallow_sc +%%-------------------------------------------------------------------- + +swallow_sc(suite) -> [swallow_sc_norm]; +swallow_sc(doc) -> ["Checks swallowing an undesirable semicolon"]. + +swallow_sc_norm(doc) -> ["Checks swallowing an undesirable semicolon."]; +swallow_sc_norm(suite) -> []; +swallow_sc_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(swallow_sc_norm), + File = filename:join(DataDir, swallow_sc), + + ?line ok = test_file(File, DataDir), + ok. + + +%%-------------------------------------------------------------------- +%% unintended_grp +%%-------------------------------------------------------------------- + +unintended_grp(suite) -> [unintended_grp_norm]; +unintended_grp(doc) -> ["Checks unintended grouping of arithmetic"]. + +unintended_grp_norm(doc) -> ["Checks unintended grouping of arithmetic."]; +unintended_grp_norm(suite) -> []; +unintended_grp_norm(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + _OutDir = ?OUT(unintended_grp_norm), + File = filename:join(DataDir, unintended_grp), + + ?line ok = test_file(File, DataDir), + ok. + + + + + +test_file(FileT, DataDir) -> + case test_file_1(FileT, DataDir) of + ok -> ok; + Chars -> + io:put_chars(Chars), + {error,{FileT,DataDir}} + end. + +test_file_1(FileT, DataDir) -> + Tok = string:tokens(FileT, "/"), + FileName = lists:last(Tok), + File = FileT++".idl", + + ?line test_server:format("File ~p~n",[File]), + ?line test_server:format("FileName ~p~n",[FileName]), + + Flags = "-I"++DataDir, + + ?line test_server:format("Flags ~p~n",[Flags]), + + ?line Erl = pp_erl(File, Flags), + ?line Gcc = pp_gcc(File, Flags), + + ?line case Erl of + {error,_ErlError} -> + ?line test_server:format("Internal_pp Result ~n==================~n~p~n~n",[Erl]); + {warning, _ErlWar} -> + ?line test_server:format("Internal_pp Result ~n==================~n~p~n~n",[Erl]); + _ -> + ?line test_server:format("Internal_pp Result ~n==================~n~s~n~n",[Erl]) + end, + + ?line case Gcc of + {error,GccError} -> + Error = string:tokens(GccError, "\n"), + ?line test_server:format(?GCC" Result ~n==========~n~p~n~n", + [Error]); + _ -> + ?line test_server:format(?GCC" Result ~n==========~n~s~n~n",[Gcc]) + end, + + + + ?line case {Erl,Gcc} of + {{warning,W}, {error,X}} -> + ?line case is_ok(W,X) of + yes -> + ok; + no -> + io_lib:format("Internal_pp found Warning = ~p ~n" + ?GCC" found Error = ~p~n",[W,X]) + end; + + + {{warning,W}, _} -> + io_lib:format(?GCC" did not find warnings while ~n" + "Internal_pp found the following Warning = ~p~n",[W]); + + {{error,E}, {error,X}} -> + ?line case is_ok(E,X) of + yes -> + ok; + no -> + io_lib:format("Internal_pp found Error = ~p ~n" + ?GCC" found Error = ~p~n",[E,X]) + end; + + {{error,E}, _} -> + ?line case FileName of + "if" -> + ?line case if_res(E) of + ok -> + ok; + _ -> + io_lib:format(?GCC" did not find errors while ~n" + "Internal_pp found the following Error = ~p~n",[E]) + end; + _ -> + io_lib:format(?GCC" did not find errors while ~n" + "Internal_pp found the following Error = ~p~n",[lists:flatten(E)]) + end; + + {_, {error,X}} -> + io_lib:format("Internal_pp did not find errors while ~n" + ?GCC" found the following Error = ~p~n",[X]); + + _ -> + + ?line file:write_file("/tmp/Erl.pp",list_to_binary(Erl)), + ?line file:write_file("/tmp/Gcc.pp",list_to_binary(Gcc)), + + ?line Res = os:cmd("diff -b -w /tmp/Erl.pp /tmp/Gcc.pp"), + ?line test_server:format("///////////{error,E} E ~p FileName~p~n",[Res,FileName]), + ?line case {Res, FileName} of + {[], _} -> + ?line test_server:format("Diff = [] OK!!!!!!~n"), + ok; + {_, "predef_time"} -> + Tokens = string:tokens(Res,"\n"), + ?line test_server:format("///////////{error,E} Tokens~p~n",[Tokens]), + case Tokens of + ["3c3",_,"---",_,"5c5",_,"---",_,"9c9",_,"---",_] -> + ok; + _ -> + io_lib:format("Diff Result = ~p~n",[Res]) + end; + _ -> + io_lib:format("Diff Result = ~p~n",[Res]) + end + end. + + + + + +pp_erl(File, Flags) -> + case ic_pp:run(File,Flags) of + {ok, [$#, $ , $1 | Rest], []} -> + [$#, $ , $1 | Rest]; + {ok, [$#, $ , $1 | _Rest], Warning} -> + {warning,Warning}; + {error,Error} -> + {error,Error} + end. + +pp_gcc(File, Flags) -> + Cmd = ?GCC" -x c++ -E", + Line = Cmd++" "++Flags++" "++File, + + case os:cmd(Line) of + [$#, $ , $1 | Rest] -> + [$#, $ , $1 | Rest]; + Res -> + + case string:str(Res,"# 1 \"") of + 0 -> + {error,Res}; + X -> + {error, string:sub_string(Res, 1, X-1)} + end + end. + + +is_ok([],_Gcc) -> + yes; +is_ok([{FileName,Line,Text}|T],Gcc) -> + Str = FileName++":"++integer_to_list(Line)++": "++Text, + case string:str(Gcc,Str) of + 0 -> + io:format("~n is_ok Internal_pp missed Error = ~s~n",[Str]), + no; + _X -> + is_ok(T,Gcc) + end; +is_ok([Str|T],Gcc) -> + case string:str(Gcc,Str) of + 0 -> + io:format("~n is_ok Internal_pp missed Error = ~s~n",[Str]), + no; + _X -> + is_ok(T,Gcc) + end. + + +to_list(X) when is_atom(X) -> atom_to_list(X); +to_list(X) -> X. + + + +if_res(E) -> + if_res(E,1). + +if_res([H|T],Nr) -> + %% Dir = "/clearcase/otp/libraries/ic/test/ic_pp_SUITE_data/if.idl", + case {Nr, H} of + {1, {_Dir, 2, "only '#if 0' is implemented at present"}} -> + if_res(T,Nr+1); + {2, {_Dir, 3, "only '#if 0' is implemented at present"}} -> + if_res(T,Nr+1); + {3, {_Dir, 5, "`else' command is not implemented at present"}} -> + if_res(T,Nr+1); + {4, {_Dir, 9, "`elif' command is not implemented at present"}} -> + if_res(T,Nr+1); + {5, {_Dir, 11, "`else' command is not implemented at present"}} -> + ok; + _ -> + error + end; +if_res(_, _) -> + error. + + + diff --git a/lib/ic/test/ic_pp_SUITE_data/arg.idl b/lib/ic/test/ic_pp_SUITE_data/arg.idl new file mode 100644 index 0000000000..b4d266121d --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/arg.idl @@ -0,0 +1,38 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define xstr (s) str(s) +#define str(s) #s +#define foo 4 + +xstr(foo); + +#define x(kalle)stina +x(kurt) +x + +#define y(kalle) stina +y(kurt) +y + +#define a(kalle) stina +a(kurt) +a + +#define b (kalle) stina +b(kurt) diff --git a/lib/ic/test/ic_pp_SUITE_data/cascade.idl b/lib/ic/test/ic_pp_SUITE_data/cascade.idl new file mode 100644 index 0000000000..8dff1ee99f --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/cascade.idl @@ -0,0 +1,29 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define BUFS 1020 +#define TABS BUFS +#undef BUFS +#define BUFS 37 + + +main() +{ + TABS; + +} diff --git a/lib/ic/test/ic_pp_SUITE_data/comment.idl b/lib/ic/test/ic_pp_SUITE_data/comment.idl new file mode 100644 index 0000000000..d2ca3e7872 --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/comment.idl @@ -0,0 +1,72 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define T 12 +#define F T + +//comment +/*exception except {};*/ + +// comment + // comment +/* another */ + /* another */ +/* still +another */ + /* still + another */ +__LINE__ +/* yet \ + another */ +// yet \ + another +__LINE__ + +#include "all.c" +#include <all.c> +#include /* comment */ "all.c" +#include /* comment */ <all.c> +#include "all.c" /* comment */ +#include <all.c> /* comment */ +#include // "all.c" +#include // <all.c> +#include "all.c" // comment +#include <all.c> // comment +#include "all/*cc*/.c" +#include <all/*cc*/.c> + +main() +{ + printf(" %d \n",F); + a(); + +} +//comment +/*exception hell {};*/ +#undef T +#define T "3/*com\ +ment*/4" +a() +{ + printf(" %d \n",F); + printf(" %d \n",T); +} + +b() +{} + diff --git a/lib/ic/test/ic_pp_SUITE_data/concat.idl b/lib/ic/test/ic_pp_SUITE_data/concat.idl new file mode 100644 index 0000000000..b8527fadfc --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/concat.idl @@ -0,0 +1,60 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define sune kurt +#define a(name) a #name name##_command +#define b(name) b #name name## _command +#define c(name) c #name name ##_command +#define d(name) d #name name ## _command +#define e(name) e #name command ## _command +#define f(name) f #name command ## %_command +#define g(name) g #name name ## %_command +#define h(name) h #name %_command ## name +#define i(name) i #name name ## _ ## name +#define j(name) j #name name ## name +#define k(name) k #name name ## name +#define l(name) l #name !name ## name +#define m(name) m #name name ## !name +#define n(name) n #name !name ## !name +#define o(name) stina +#define p(name) name +#define q1(name) q1 #name j(name) ## j(name) +#define q2(name) q2 #name j(name) +#define q3(name) q3 #name !! ## j(name) +#define q4(name) q4 #name ## j(name) + +a(quit) +b(quit) +c(quit) +d(quit) +e(quit) +f(quit) +g(sune) +h(sune) +i(sune) +j(sune) +l(sune) +m(sune) +n(sune) +k(j(sune)) +k(o(sune)) +k(p(sune)) +q1(sune) +q2(sune) +q3(sune) +q4(sune) diff --git a/lib/ic/test/ic_pp_SUITE_data/define.idl b/lib/ic/test/ic_pp_SUITE_data/define.idl new file mode 100644 index 0000000000..6aac63dd1e --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/define.idl @@ -0,0 +1,41 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define 8 +#define +#define a +#define _a +#define b dfs +#define 9 fdas +#define a8 +#define A +#define (c) fadfas +#define )c) fadfas +#define % c) fadfas +#define d(p) kfdsa +#define e(p) sinus(p) +#warning warning line +#define w%er percent +#define q() no_para +#warning warning line +#undef +#undef 8 +#undef a +#undef b +#undef _a d(kk) + diff --git a/lib/ic/test/ic_pp_SUITE_data/if.idl b/lib/ic/test/ic_pp_SUITE_data/if.idl new file mode 100644 index 0000000000..c381fa73ee --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/if.idl @@ -0,0 +1,32 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define kurt 12 +#if !true +#if X == 1 +ett +#else +else +#endif +true +#elif kurt +trueelif +#else +trueelse +#endif +end diff --git a/lib/ic/test/ic_pp_SUITE_data/if_zero.idl b/lib/ic/test/ic_pp_SUITE_data/if_zero.idl new file mode 100644 index 0000000000..d715f9d61e --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/if_zero.idl @@ -0,0 +1,31 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#if 0 +pelle = mallan +#endif +pelle = stina +#if 0 +kalle = stina +#endif +kalle = mallan +#if 0 +kurt = fia +#endif +fia = kurt + diff --git a/lib/ic/test/ic_pp_SUITE_data/improp_nest_constr.idl b/lib/ic/test/ic_pp_SUITE_data/improp_nest_constr.idl new file mode 100644 index 0000000000..463ee3c695 --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/improp_nest_constr.idl @@ -0,0 +1,30 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define double(x) (2*(x)) +#define call_with_1(x) x(1) + +#define strange(file) fprintf (file, "%s %d", + +main() +{ + call_with_1(double); + strange(stderr) p, 35) + +} + diff --git a/lib/ic/test/ic_pp_SUITE_data/inc.idl b/lib/ic/test/ic_pp_SUITE_data/inc.idl new file mode 100644 index 0000000000..0dcd637082 --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/inc.idl @@ -0,0 +1,68 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +int x; + +#include "head.h" +#warning line nr +main() +{ + printf(test()); +} + + + + + + + + +#define C false +#define Z on +#include "inc2.h" +#undef Z +"Ca" C +"Za" Z +#include "inc2.h" +"Cb" C +"Zb" Z + +main() +{ +#define Q(a,b) sinus(a,b kurt ## b) + if (Q(34,56)=='NULL') printf(" T AAA%sEEEE \n",Q); + printf(" %d \n",F); + a(); +} +//comment +/*exception +hell {};*/ +#undef T +#define T "3/*com\ment*/4" +#define T 33 +#define F again +a () +{ + printf(" %d \n",F); + printf(" %d \n",T); +} + +b() +{} + diff --git a/lib/ic/test/ic_pp_SUITE_data/included1.idl b/lib/ic/test/ic_pp_SUITE_data/included1.idl new file mode 100644 index 0000000000..4cd26c4543 --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/included1.idl @@ -0,0 +1,35 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 2000-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#ifndef INCLUDED1_IDL +#define INCLUDED1_IDL + + +#ifndef SOMETHING +#endif + + +struct s { + + long l; + +}; + + + +#endif diff --git a/lib/ic/test/ic_pp_SUITE_data/included2.idl b/lib/ic/test/ic_pp_SUITE_data/included2.idl new file mode 100644 index 0000000000..7cc44eef3e --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/included2.idl @@ -0,0 +1,41 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 2000-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#ifndef INCLUDED2_IDL +#define INCLUDED2_IDL + +#include "included1.idl" + + +#ifdef SOMETHING +#endif + + +module m { + + struct t { + + s st; + + }; + + +}; + + +#endif diff --git a/lib/ic/test/ic_pp_SUITE_data/includer.idl b/lib/ic/test/ic_pp_SUITE_data/includer.idl new file mode 100644 index 0000000000..c6ebc234e8 --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/includer.idl @@ -0,0 +1,45 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 2000-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#ifndef INCLUDER_IDL +#define INCLUDER_IDL + +#include "included1.idl" +#include "included2.idl" + +#ifdef SOMETHING +#endif + + + +module n { + + interface j { + + s op(in m::t inpar); + + }; + +}; + + + + +#endif + + diff --git a/lib/ic/test/ic_pp_SUITE_data/line.idl b/lib/ic/test/ic_pp_SUITE_data/line.idl new file mode 100644 index 0000000000..5bd9c9446d --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/line.idl @@ -0,0 +1,45 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#line +#line 8 +#line 8a +#line 12 abc.c +#line 12 "kurt.c" +#warning fdafdsaf + + +#define T 12 +#define F T +#define Q(a) sinus(a) +#undef Q +# +#line 12 +#warning test of warning +#warning second of warning +#warning third of warning +#pragma kurt +#ident kurt +#kurt fdsafd +#line 20 +main() +{ + if (Q(34,56)=='NULL') printf(" T AAA%sEEEE \n",Q); + printf(" %d \n",F); +} +sune diff --git a/lib/ic/test/ic_pp_SUITE_data/misc.idl b/lib/ic/test/ic_pp_SUITE_data/misc.idl new file mode 100644 index 0000000000..9c18610fcf --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/misc.idl @@ -0,0 +1,44 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define str(s) #s +str(fool); +str(foo); +str(kurt); +#define xstr(s) str(s) +#define foo 4 +#define kurt sune +#define sune 17 + +xstr(fool); +xstr(foo); +xstr(kurt); + +#define a(b) b #8b +#define r(b) b # +#define t(b) b ## a +a(sinus) + +#define ww #www +ww + +#define x 14 + y +#define y 12 + #x +x + +#define e(a) cosinus(a) diff --git a/lib/ic/test/ic_pp_SUITE_data/nopara.idl b/lib/ic/test/ic_pp_SUITE_data/nopara.idl new file mode 100644 index 0000000000..1bb137da11 --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/nopara.idl @@ -0,0 +1,35 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#11a +#define xstr str(s) + kurt*2; +#define asdf pragma +#asdf +#define asd #pragma asd + +#10 +#12 8kurt + +#define sss "stringing in the rain" +#define ddd "string +ing in the rain" asd +#line 20 +#include "head.h" qqqq +#include %!# +#include <sys.h> + diff --git a/lib/ic/test/ic_pp_SUITE_data/predef.idl b/lib/ic/test/ic_pp_SUITE_data/predef.idl new file mode 100644 index 0000000000..d8abcb25d5 --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/predef.idl @@ -0,0 +1,33 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define b(q,w) kurt q w + + +b(__LINE__, __FILE__) +__LINE__ +__FILE__ + + + +b(__INCLUDE_LEVEL__, __BASE_FILE__) +__INCLUDE_LEVEL__ +__BASE_FILE__ + +Line __LINE__ +#include "predef.h" diff --git a/lib/ic/test/ic_pp_SUITE_data/predef_time.idl b/lib/ic/test/ic_pp_SUITE_data/predef_time.idl new file mode 100644 index 0000000000..05e3ba9175 --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/predef_time.idl @@ -0,0 +1,24 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define b(q,w) kurt q w +b(__DATE__, __TIME__) +__DATE__ +__TIME__ + +#include "predef_time.h" diff --git a/lib/ic/test/ic_pp_SUITE_data/self_ref.idl b/lib/ic/test/ic_pp_SUITE_data/self_ref.idl new file mode 100644 index 0000000000..a44666272e --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/self_ref.idl @@ -0,0 +1,26 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define foo (4 + foo) + + +main() +{ + foo; + +} diff --git a/lib/ic/test/ic_pp_SUITE_data/separate.idl b/lib/ic/test/ic_pp_SUITE_data/separate.idl new file mode 100644 index 0000000000..a3faf9b986 --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/separate.idl @@ -0,0 +1,37 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define xstr(s) str(s) +#define str(s) #s +#define foo 4 +#define str1(s) #s lose(s) +#define foo1 4 + +main() +{ + str(foo); + str1(foo1); + xstr(foo); + +#define qxstr(s) qstr(s) + qxstr(qfoo); +#define qstr(s) #s + qstr( 4 ) ; +#define qfoo 4 + qstr(qfoo); +} diff --git a/lib/ic/test/ic_pp_SUITE_data/swallow_sc.idl b/lib/ic/test/ic_pp_SUITE_data/swallow_sc.idl new file mode 100644 index 0000000000..71ed329ca6 --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/swallow_sc.idl @@ -0,0 +1,37 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +/* comment \ + ends */ +// comment\ +ends +Line __LINE__ +#define SKIP_SPACES(p, limit) \ +{register char *lim = (limit); \ + while (p != lim) { \ + if (*p++ != ' ') { \ + p--; break; }}} + + +main() +{ + if (*p != 0) + SKIP_SPACES (ppp, lim); + else + a = 17; +} diff --git a/lib/ic/test/ic_pp_SUITE_data/unintended_grp.idl b/lib/ic/test/ic_pp_SUITE_data/unintended_grp.idl new file mode 100644 index 0000000000..3618bab1bc --- /dev/null +++ b/lib/ic/test/ic_pp_SUITE_data/unintended_grp.idl @@ -0,0 +1,29 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +#define ceil_div( xz, yz) (xz + yz - 1) / yz +#define ceil_div2(xz, yz) ((xz) + (yz) - 1) / (yz) + +#define b kurt + +main() +{ + ceil_div(b & c, sizeof(int)); + ceil_div2(b & c, sizeof(int)); + +} diff --git a/lib/ic/test/ic_pragma_SUITE.erl b/lib/ic/test/ic_pragma_SUITE.erl new file mode 100644 index 0000000000..0edb5d4717 --- /dev/null +++ b/lib/ic/test/ic_pragma_SUITE.erl @@ -0,0 +1,295 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: ic_pragma_SUITE.erl +%% +%% Description: +%% Test suite for the IFR object registration when +%% pragmas are engaged +%% +%%----------------------------------------------------------------- +-module(ic_pragma_SUITE). + +-include("test_server.hrl"). +-include_lib("orber/include/corba.hrl"). +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([all/1, init_all/1, finish_all/1]). +-export([ifr_pragma_reg/1, pragma_error/1, uggly_pragmas/1]). + + +%%----------------------------------------------------------------- +%% Macros +%%----------------------------------------------------------------- +-define(REMAP_EXCEPT(F), case catch F of + {'EXCEPTION', E} -> exit(E); + R -> R + end). +%% Standard options to the ic compiler, NOTE unholy use of OutDir + +-define(OUT(X), filename:join([?config(priv_dir, Config), gen, to_list(X)])). + + +%%----------------------------------------------------------------- +%% Func: all/1 +%% Args: +%% Returns: +%%----------------------------------------------------------------- +all(doc) -> ["Description", "more description"]; +all(suite) -> {req, + [mnesia], + {conf, init_all, cases(), finish_all}}. + +cases() -> + [ifr_pragma_reg,pragma_error,uggly_pragmas]. + +%%----------------------------------------------------------------- +%% Init and cleanup functions. +%%----------------------------------------------------------------- +init_all(Config) -> + io:format("Setting up.....~n"), + mnesia:stop(), + mnesia:delete_schema([node()]), + mnesia:create_schema([node()]), + mnesia:start(), + orber:install([node()]), + orber:start(), + if + is_list(Config) -> + Config; + true -> + exit("Config not a list") + end. + +finish_all(Config) -> + io:format("Setting down.....~n"), + orber:stop(), + orber:uninstall(), + mnesia:stop(), + mnesia:delete_schema([node()]), + Config. + + + + +%%----------------------------------------------------------------- +%% Test Case: IFR registration with pragmas +%%----------------------------------------------------------------- +ifr_pragma_reg(doc) -> + ["Checks that IFR object is correctly registered under pragma engagement."]; +ifr_pragma_reg(suite) -> []; +ifr_pragma_reg(Config) when is_list(Config) -> + ?REMAP_EXCEPT(ifr_pragma_reg_run(Config)). + +ifr_pragma_reg_run(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(ifr_pragma_reg), + File0 = filename:join(DataDir, reg_m0), + ?line ok = ic:gen(File0, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}]), + ?line ok = compile(OutDir, ifr_pragma_files()), + code:add_pathz(OutDir), + + %% OE_register for all files + ?line ok = 'oe_reg_m0':'oe_register'(), + + %% Pragma registration test + OE_IFR = orber_ifr:find_repository(), + io:format("~n##### Starting the test case #####~n"), + check_pragma_effect(OE_IFR,"IDL:M1/T1:1.0"), + check_pragma_effect(OE_IFR,"DCE:d62207a2-011e-11ce-88b4-0800090b5d3e:3"), + check_pragma_effect(OE_IFR,"IDL:P2/T3:1.0"), + check_pragma_effect(OE_IFR,"IDL:P1/M2/T4:2.4"), + + %% OE_unregister for all files + ?line ok = 'oe_reg_m0':'oe_unregister'(), + code:del_path(OutDir), + ok. + + +ifr_pragma_files() -> ['oe_reg_m0']. + + +check_pragma_effect(OE_IFR,ID) -> + io:format("Checking for existance of : ~s~n",[ID]), + case orber_ifr:lookup_id(OE_IFR,ID) of + [] -> + test_server:fail(ID ++ " does not exist"), + false; + {Def,_} -> + io:format("Id refers to = {~p,#Bin}~n",[Def]), + true + end. + + + + +%%----------------------------------------------------------------- +%% Test Case: Syntactical / Semantical error pragma definitions +%%----------------------------------------------------------------- +pragma_error(doc) -> + ["Finds errornous pragma definitions under compilation."]; +pragma_error(suite) -> []; +pragma_error(Config) when is_list(Config) -> + ?REMAP_EXCEPT(pragma_error_run(Config)). + +pragma_error_run(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(pragma_error), + File1 = filename:join(DataDir, reg_m1), + File2 = filename:join(DataDir, reg_m2), + File3 = filename:join(DataDir, reg_m3), + File4 = filename:join(DataDir, reg_m4), + File5 = filename:join(DataDir, reg_m5), + File6 = filename:join(DataDir, reg_m6), + + ?line error = ic:gen(File1, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + + ?line error = ic:gen(File2, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + + ?line error = ic:gen(File3, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + + ?line ok = ic:gen(File4, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + + ?line error = ic:gen(File5, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + + ?line error = ic:gen(File6, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ok. + + + + +%%----------------------------------------------------------------- +%% Test Case: IFR registration with realy uggly placed pragmas +%%----------------------------------------------------------------- +uggly_pragmas(doc) -> + ["Checks that IFR object is correctly registered under really uggly pragma engagement."]; +uggly_pragmas(suite) -> []; +uggly_pragmas(Config) when is_list(Config) -> + ?REMAP_EXCEPT(uggly_pragmas_run(Config)). + +uggly_pragmas_run(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(ifr_pragma_reg), + File0 = filename:join(DataDir, uggly), + + ?line ok = ic:gen(File0, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}]), + + ?line ok = compile(OutDir, uggly_pragma_files()), + code:add_pathz(OutDir), + + %% OE_register for all files + ?line ok = 'oe_uggly':'oe_register'(), + + %% Pragma registration test + OE_IFR = orber_ifr:find_repository(), + io:format("~n##### Starting the test case #####~n"), + + check_pragma_effect(OE_IFR, "IDL:M:1.0"), + check_pragma_effect(OE_IFR, "LOCAL:SomeLocalId:10"), + check_pragma_effect(OE_IFR, "LOCAL:SomeLocalId:11"), + check_pragma_effect(OE_IFR, "LOCAL:SomeLocalId:17"), + check_pragma_effect(OE_IFR, "LOCAL:SomeLocalId:34"), + check_pragma_effect(OE_IFR, "IDL:Exc1:2.2"), + check_pragma_effect(OE_IFR, "IDL:Exc2:2.2"), + check_pragma_effect(OE_IFR, "IDL:S:1.0"), + check_pragma_effect(OE_IFR, "IDL:U:1.0"), + check_pragma_effect(OE_IFR, "LOCAL:SomeLocalId:23"), + + %% OE_unregister for all files + ?line ok = 'oe_uggly':'oe_unregister'(), + + code:del_path(OutDir), + ok. + + +uggly_pragma_files() -> ['oe_uggly']. + + + + +%%---------------------------- + + +stdopts(OutDir) -> + [{outdir, OutDir}, {maxerrs, infinity}]. + + +compile(Dir, Files) -> + compile(Dir, Files, []). + +compile(Dir, Files, Opts) -> + {ok, Cwd} = file:get_cwd(), + file:set_cwd(Dir), + io:format("Changing to ~p~n", [Dir]), + case catch do_compile(Files, Opts) of + ok -> + file:set_cwd(Cwd); + Err -> + file:set_cwd(Cwd), + test_server:fail(Err) + end. + +do_compile([], _Opts) -> ok; +do_compile([F | Fs], Opts) -> + io:format("Compiling ~p", [F]), + case compile:file(F, Opts) of + ok -> + io:format(" ok~n", []), + do_load(F, Opts), + do_compile(Fs, Opts); + {ok, _} -> + io:format(" ok~n", []), + do_load(F, Opts), + do_compile(Fs, Opts); + {ok, _, _} -> + io:format(" ok~n", []), + do_load(F, Opts), + do_compile(Fs, Opts); + Err -> + io:format(" error: ~p~n", [Err]), + Err + end. + +do_load(File, Opts) -> + case lists:member(load, Opts) of + true -> + io:format("Loading file ~p", [File]), + code:purge(File), + R = code:load_abs(File), + io:format("Loaded: ~p", [R]); + false -> + ok + end. + + +to_list(X) when is_atom(X) -> atom_to_list(X); +to_list(X) -> X. + + + diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m0.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m0.idl new file mode 100644 index 0000000000..80f0f2cdd1 --- /dev/null +++ b/lib/ic/test/ic_pragma_SUITE_data/reg_m0.idl @@ -0,0 +1,77 @@ + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Normal pragmas + +module M1 { + + typedef long T1; + + typedef long T2; + +#pragma ID T2 "DCE:d62207a2-011e-11ce-88b4-0800090b5d3e:3" + +}; + + +#pragma prefix "P1" + +module M2 { + + module M3 { + +#pragma prefix "P2" + + interface I1 { + void Op( in short b, + out short c); + }; + typedef long T3; + }; + + + typedef long T4; + +#pragma version T4 2.4 + +}; + + + +/* + + Specified types with the following scoped names + and RepositoryIds + + ::M1::T1 IDL:M1/T1:1.0 + + ::M1::T2 DCE:d62207a2-011e-11ce-88b4-0800090b5d3e:3 + + ::M2::M3::T3 IDL:P2/T3:1.0 + + ::M2::T4 IDL:P1/M2/T4:2.4 + +*/ + + + + + + + + diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m1.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m1.idl new file mode 100644 index 0000000000..6c22788290 --- /dev/null +++ b/lib/ic/test/ic_pragma_SUITE_data/reg_m1.idl @@ -0,0 +1,75 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// Bad pragma IDs + +// Completelly bad id +module M1 { + + typedef long T1; + + typedef long T2; + +#pragma ID T2 "CompletelyBadId" + +}; + + +// Bad id, should start with DCE +module M2 { + + typedef long T1; + + typedef long T2; + +#pragma ID T2 "BAD:d62207a2-011e-11ce-88b4-0800090b5d3e:3" + +}; + + +// Bad version in ID : not a short number +module M3 { + + typedef long T1; + + typedef long T2; + +#pragma ID T2 "DCE:d62207a2-011e-11ce-88b4-0800090b5d3e:ABCD" + +}; + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m2.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m2.idl new file mode 100644 index 0000000000..1751751295 --- /dev/null +++ b/lib/ic/test/ic_pragma_SUITE_data/reg_m2.idl @@ -0,0 +1,40 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// Bad pragma versions + + +// Bad major version : not a short number +module M1 { + + typedef long T4; + +#pragma version T4 2000000000.4 + +}; + +// Bad minor version : not a short number +module M2 { + + typedef long T4; + +#pragma version T4 2.4000000000000 + +}; + + diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m3.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m3.idl new file mode 100644 index 0000000000..b7c9da249f --- /dev/null +++ b/lib/ic/test/ic_pragma_SUITE_data/reg_m3.idl @@ -0,0 +1,38 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// Bad pragma prefixs + +module M2 { + + module M3 { + +#pragma prefix P2 // Should be "P2" + + interface I1 { + void foo( in short b, + out short c); + }; + typedef long T3; + }; + + + typedef long T4; +}; + + diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m4.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m4.idl new file mode 100644 index 0000000000..0c7079e3dd --- /dev/null +++ b/lib/ic/test/ic_pragma_SUITE_data/reg_m4.idl @@ -0,0 +1,64 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// Unrecognmizable pragmas + +module M1 { + + typedef long T1; + + typedef long T2; + + + // Should be ID directive + +#pragma ShouldBeId T2 "DCE:d62207a2-011e-11ce-88b4-0800090b5d3e:3" + +}; + + // Should be prefix directive + +#pragma ShouldBePrefix "P1" + +module M2 { + + module M3 { + + // Should be prefix directive + +#pragma ShouldBePrefix "P2" + + interface I1 { + void foo( in short b, + out short c); + }; + typedef long T3; + }; + + + typedef long T4; + + + // Should be version + +#pragma ShouldBeVersion T4 2.4 + +}; + + + diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m5.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m5.idl new file mode 100644 index 0000000000..cbf053fac4 --- /dev/null +++ b/lib/ic/test/ic_pragma_SUITE_data/reg_m5.idl @@ -0,0 +1,28 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Version not in valid form : major.ninor + +module M1 { + + typedef long T4; + + #pragma version T4 2 + +}; diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m6.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m6.idl new file mode 100644 index 0000000000..b7c9da249f --- /dev/null +++ b/lib/ic/test/ic_pragma_SUITE_data/reg_m6.idl @@ -0,0 +1,38 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// Bad pragma prefixs + +module M2 { + + module M3 { + +#pragma prefix P2 // Should be "P2" + + interface I1 { + void foo( in short b, + out short c); + }; + typedef long T3; + }; + + + typedef long T4; +}; + + diff --git a/lib/ic/test/ic_pragma_SUITE_data/reg_m7.idl b/lib/ic/test/ic_pragma_SUITE_data/reg_m7.idl new file mode 100644 index 0000000000..349c13b244 --- /dev/null +++ b/lib/ic/test/ic_pragma_SUITE_data/reg_m7.idl @@ -0,0 +1,62 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% + +// Very uggly pragmas + + +#pragma prefix "P1" // Normal pragma + +module M4 { + + module M5 { + +#pragma prefix "P2" // Inside a parameter list + + interface I1 { + void Op( + #pragma prefix "P2" // Inside a parameter list + in short b, + #pragma prefix "P2" // Inside a parameter list + out short c + #pragma prefix "P2" // Inside a parameter list + ); + }; + typedef long T3; + }; + +}; + + + +/* + + Specified types with the following scoped names + and RepositoryIds + + ::M4::M5::T3 IDL:P2/T3:1.0 + +*/ + + + + + + + + diff --git a/lib/ic/test/ic_pragma_SUITE_data/uggly.idl b/lib/ic/test/ic_pragma_SUITE_data/uggly.idl new file mode 100644 index 0000000000..8ed3ac57ec --- /dev/null +++ b/lib/ic/test/ic_pragma_SUITE_data/uggly.idl @@ -0,0 +1,204 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// Really uggly pragmas + + +struct S { + +#pragma ID TDL1 "LOCAL:SomeLocalId:1" +#pragma ID TDL1 "LOCAL:SomeLocalId:2" + +long a + +#pragma ID TDL1 "LOCAL:SomeLocalId:3" +#pragma ID TDL1 "LOCAL:SomeLocalId:4" + +; + +#pragma ID TDL1 "LOCAL:SomeLocalId:5" +#pragma ID TDL1 "LOCAL:SomeLocalId:6" + +long b + +#pragma ID TDL1 "LOCAL:SomeLocalId:7" +#pragma ID TDL1 "LOCAL:SomeLocalId:8" + +; + + +#pragma ID TDL1 "LOCAL:SomeLocalId:9" +#pragma ID TDL1 "LOCAL:SomeLocalId:10" + +}; + + +typedef long TDL1; + + +exception Exc1{ + +#pragma version Exc1 2.2 +#pragma ID TDL2 "LOCAL:SomeLocalId:11" + +}; + + +typedef long TDL2; + + +exception Exc2 { + +#pragma version Exc2 2.2 +#pragma ID TDL3 "LOCAL:SomeLocalId:11" + + long a + +#pragma ID TDL3 "LOCAL:SomeLocalId:12" +#pragma ID TDL3 "LOCAL:SomeLocalId:13" + + ; + +#pragma ID TDL3 "LOCAL:SomeLocalId:14" +#pragma ID TDL3 "LOCAL:SomeLocalId:15" + + long b + +#pragma ID TDL3 "LOCAL:SomeLocalId:16" + + ; + +#pragma ID TDL3 "LOCAL:SomeLocalId:17" + + +}; + +typedef long TDL3; + +enum E { +#pragma ID E "LOCAL:SomeLocalId:18" + a +#pragma ID E "LOCAL:SomeLocalId:19" + , +#pragma ID E "LOCAL:SomeLocalId:20" + b +#pragma ID E "LOCAL:SomeLocalId:21" +, +#pragma ID E "LOCAL:SomeLocalId:22" + c +#pragma ID E "LOCAL:SomeLocalId:23" +}; + + + +union U switch (long) { + +#pragma ID TDL4 "LOCAL:SomeLocalId:24" + + case 1: + +#pragma ID TDL4 "LOCAL:SomeLocalId:25" + + long a + +#pragma ID TDL4 "LOCAL:SomeLocalId:26" + +; + +#pragma ID TDL4 "LOCAL:SomeLocalId:27" + + case 2: + +#pragma ID TDL4 "LOCAL:SomeLocalId:28" + + case 3: + +#pragma ID TDL4 "LOCAL:SomeLocalId:29" + +long b + +#pragma ID TDL4 "LOCAL:SomeLocalId:30" + +; + +#pragma ID TDL4 "LOCAL:SomeLocalId:31" + + default : + +#pragma ID TDL4 "LOCAL:SomeLocalId:32" + +long c + +#pragma ID TDL4 "LOCAL:SomeLocalId:33" + +; + +#pragma ID TDL4 "LOCAL:SomeLocalId:34" + +}; + + +typedef long TDL4; + + + +module M { + + interface I { + + void fun1( + +#pragma version fun1 3.0 +#pragma ID TDL5 "LOCAL:SomeLocalId:35" + + in short b + +#pragma ID TDL5 "LOCAL:SomeLocalId:36" +#pragma ID TDL5 "LOCAL:SomeLocalId:37" + + , + +#pragma ID TDL5 "LOCAL:SomeLocalId:38" +#pragma ID TDL5 "LOCAL:SomeLocalId:39" + + out short c + +#pragma ID TDL5 "LOCAL:SomeLocalId:40" +#pragma ID TDL5 "LOCAL:SomeLocalId:41" + + ); + + + typedef long TDL5; + + + void fun2( + +#pragma ID TDL6 "LOCAL:SomeLocalId:42" +#pragma ID TDL6 "LOCAL:SomeLocalId:43" + + ); + + typedef long TDL6; + + }; + + + +}; + diff --git a/lib/ic/test/ic_register_SUITE.erl b/lib/ic/test/ic_register_SUITE.erl new file mode 100644 index 0000000000..ae7578199a --- /dev/null +++ b/lib/ic/test/ic_register_SUITE.erl @@ -0,0 +1,425 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%----------------------------------------------------------------- +%% File: ic_register_SUITE.erl +%% +%% Description: +%% Test suite for the IFR object registration +%% +%%----------------------------------------------------------------- +-module(ic_register_SUITE). + +-include("test_server.hrl"). +-include_lib("orber/include/corba.hrl"). +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- +-export([all/1, init_all/1, finish_all/1, ifr_reg_unreg/1]). +-export([ifr_inheritence_reg/1,ifr_reg_unreg_with_inheritence/1]). +-export([ifr_reg_unreg_with_inheritence_bad_order/1]). + +%%----------------------------------------------------------------- +%% Internal exports +%%----------------------------------------------------------------- +-export([]). + +%%----------------------------------------------------------------- +%% Macros +%%----------------------------------------------------------------- +-define(REMAP_EXCEPT(F), case catch F of + {'EXCEPTION', E} -> exit(E); + R -> R + end). +%% Standard options to the ic compiler, NOTE unholy use of OutDir + +-define(OUT(X), filename:join([?config(priv_dir, Config), gen, to_list(X)])). + + +%%----------------------------------------------------------------- +%% Func: all/1 +%% Args: +%% Returns: +%%----------------------------------------------------------------- +all(doc) -> ["Description", "more description"]; +all(suite) -> {req, + [mnesia], + {conf, init_all, cases(), finish_all}}. + +cases() -> + [ifr_reg_unreg,ifr_reg_unreg_with_inheritence, + ifr_reg_unreg_with_inheritence_bad_order,ifr_inheritence_reg]. + +%%----------------------------------------------------------------- +%% Init and cleanup functions. +%%----------------------------------------------------------------- + +init_all(Config) -> + io:format("Setting up.....~n"), + mnesia:stop(), + mnesia:delete_schema([node()]), + mnesia:create_schema([node()]), + mnesia:start(), + orber:install([node()]), + orber:start(), + if + is_list(Config) -> + Config; + true -> + exit("Config not a list") + end. + +finish_all(Config) -> + io:format("Setting down.....~n"), + orber:stop(), + orber:uninstall(), + mnesia:stop(), + mnesia:delete_schema([node()]), + Config. + + + +%%----------------------------------------------------------------- +%% Test Case: IFR type registration +%%----------------------------------------------------------------- +ifr_reg_unreg(doc) -> + ["Checks that the generated register/unregister " + "code for the IFR is correct."]; +ifr_reg_unreg(suite) -> []; +ifr_reg_unreg(Config) when is_list(Config) -> + ?REMAP_EXCEPT(ifr_reg_unregt_run(Config)). + +ifr_reg_unregt_run(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(ifr_reg_unreg), + File0 = filename:join(DataDir, reg_m8), + File1 = filename:join(DataDir, reg_m9), + File2 = filename:join(DataDir, reg_m10), + ?line ok = ic:gen(File0, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File0, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File1, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File1, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File2, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File2, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = compile(OutDir, ifr_reg_unreg_files()), + code:add_pathz(OutDir), + ?line ok = 'oe_reg_m8':'oe_register'(), + ?line ok = 'oe_reg_m9':'oe_register'(), + ?line ok = 'oe_reg_m10':'oe_register'(), + ?line ok = 'oe_reg_m10':'oe_unregister'(), + ?line ok = 'oe_reg_m9':'oe_unregister'(), + ?line ok = 'oe_reg_m8':'oe_unregister'(), + code:del_path(OutDir), + ok. + +ifr_reg_unreg_files() -> ['oe_reg_m8', 'oe_reg_m9', 'oe_reg_m10']. + + + +%%----------------------------------------------------------------- +%% Test Case: IFR registration when object inheritence +%% is applied and registered. +%%----------------------------------------------------------------- +ifr_reg_unreg_with_inheritence(doc) -> + ["Checks that the generated register/unregister " + "code for the IFR is correct, and works even when" + "the object inheritence is registered. This fixes" + "two bugs in ifr that caused crash when trying to" + "use OE_register/OE_unregister in a sequence of" + "compiled files that contained interfaces who" + "inherited others in sequence."]; +ifr_reg_unreg_with_inheritence(suite) -> []; +ifr_reg_unreg_with_inheritence(Config) when is_list(Config) -> + ?REMAP_EXCEPT(ifr_reg_unreg_with_inheritence_run(Config)). + +ifr_reg_unreg_with_inheritence_run(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(ifr_reg_unreg), + File0 = filename:join(DataDir, reg_m8), + File1 = filename:join(DataDir, reg_m9), + File2 = filename:join(DataDir, reg_m10), + File3 = filename:join(DataDir, reg_m11), + File4 = filename:join(DataDir, reg_m12), + ?line ok = ic:gen(File0, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File0, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File1, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File1, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File2, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File2, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File3, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File3, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File4, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File4, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = compile(OutDir, ifr_reg_unreg_with_inheritence_files()), + code:add_pathz(OutDir), + ?line ok = 'oe_reg_m8':'oe_register'(), + ?line ok = 'oe_reg_m9':'oe_register'(), + ?line ok = 'oe_reg_m10':'oe_register'(), + ?line ok = 'oe_reg_m11':'oe_register'(), + ?line ok = 'oe_reg_m12':'oe_register'(), + ?line ok = 'oe_reg_m8':'oe_unregister'(), + ?line ok = 'oe_reg_m9':'oe_unregister'(), + ?line ok = 'oe_reg_m10':'oe_unregister'(), + ?line ok = 'oe_reg_m11':'oe_unregister'(), + ?line ok = 'oe_reg_m12':'oe_unregister'(), + code:del_path(OutDir), + ok. + +ifr_reg_unreg_with_inheritence_files() -> + ['oe_reg_m8', 'oe_reg_m9', 'oe_reg_m10', 'oe_reg_m11', 'oe_reg_m12']. + + + + + +%%----------------------------------------------------------------- +%% Test Case: IFR registration when object inheritence +%% is applied and registered in a bad order. +%% Modules included and used from an ifr object +%% are not allready registered when the current +%% object is getting registered. +%%----------------------------------------------------------------- +ifr_reg_unreg_with_inheritence_bad_order(doc) -> + ["This tests that ifr registration is done with + the right write order." + "Modules included and used from an ifr object" + "are tested if allready registered when the " + "current object is getting registered."]; +ifr_reg_unreg_with_inheritence_bad_order(suite) -> []; +ifr_reg_unreg_with_inheritence_bad_order(Config) when is_list(Config) -> + ?REMAP_EXCEPT(ifr_reg_unreg_with_inheritence_bad_order_run(Config)). + +ifr_reg_unreg_with_inheritence_bad_order_run(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(ifr_reg_unreg), + File1 = filename:join(DataDir, reg_m9), + File2 = filename:join(DataDir, reg_m10), + File4 = filename:join(DataDir, reg_m12), + ?line ok = ic:gen(File1, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File1, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File2, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File2, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File4, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File4, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = compile(OutDir, ifr_reg_unreg_with_inheritence_files()), + code:add_pathz(OutDir), + case catch 'oe_reg_m12':'oe_register'() of + {'EXIT',Reason1} -> + io:format("IFR object missing detected : ~p~n",[Reason1]), + true; + _ -> + test_server:fail("Failed to detect object missing : IDL:M1:1.0~n") + end, + ?line ok = 'oe_reg_m9':'oe_register'(), + case catch 'oe_reg_m10':'oe_register'() of + {'EXIT',Reason2} -> + io:format("IFR object missing detected : ~p~n",[Reason2]), + true; + _ -> + test_server:fail("Failed to detect object missing : IDL:M0:1.0~n") + end, + ?line ok = 'oe_reg_m9':'oe_unregister'(), + code:del_path(OutDir), + ok. + + + +%%----------------------------------------------------------------- +%% Test Case: IFR registration with inheritence +%%----------------------------------------------------------------- +ifr_inheritence_reg(doc) -> + ["Checks that IFR object inheritence is correctly registered."]; +ifr_inheritence_reg(suite) -> []; +ifr_inheritence_reg(Config) when is_list(Config) -> + ?REMAP_EXCEPT(ifr_inh_reg_run(Config)). + +ifr_inh_reg_run(Config) -> + DataDir = ?config(data_dir, Config), + OutDir = ?OUT(ifr_reg_unreg), + File0 = filename:join(DataDir, reg_m8), + File1 = filename:join(DataDir, reg_m9), + File2 = filename:join(DataDir, reg_m10), + File3 = filename:join(DataDir, reg_m11), + File4 = filename:join(DataDir, reg_m12), + ?line ok = ic:gen(File0, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File0, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File1, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File1, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File2, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File2, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File3, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File3, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = ic:gen(File4, stdopts(OutDir)++[{preproc_flags, + "-I" ++ DataDir}] ), + ?line {ok, []} = ic:gen(File4, stdopts(OutDir)++[silent2, {preproc_flags, + "-I" ++ DataDir}]), + ?line ok = compile(OutDir, ifr_reg_unreg_with_inheritence_files()), + code:add_pathz(OutDir), + %% OE_register for all files + ?line ok = 'oe_reg_m8':'oe_register'(), + ?line ok = 'oe_reg_m9':'oe_register'(), + ?line ok = 'oe_reg_m10':'oe_register'(), + ?line ok = 'oe_reg_m11':'oe_register'(), + ?line ok = 'oe_reg_m12':'oe_register'(), + + %% Inheritence registration test + OE_IFR = orber_ifr:find_repository(), + %% Interfaces that not inherit from other interfaces + ?line [] = get_inh(OE_IFR, "IDL:m0/i0:1.0"), + ?line [] = get_inh(OE_IFR, "IDL:m1/i1:1.0"), + ?line [] = get_inh(OE_IFR, "IDL:m3/i3:1.0"), + %% Interfaces that inherit from other interfaces + ?line ["IDL:m1/i1:1.0"] = get_inh(OE_IFR, "IDL:m2/i2:1.0"), + ?line ["IDL:m1/i1:1.0","IDL:m2/i2:1.0"] = get_inh(OE_IFR, "IDL:m4/i4:1.0"), + ?line ["IDL:m3/i3:1.0"] = get_inh(OE_IFR, "IDL:m4/i5:1.0"), + + %% OE_unregister for all files + ?line ok = 'oe_reg_m8':'oe_unregister'(), + ?line ok = 'oe_reg_m9':'oe_unregister'(), + ?line ok = 'oe_reg_m10':'oe_unregister'(), + ?line ok = 'oe_reg_m11':'oe_unregister'(), + ?line ok = 'oe_reg_m12':'oe_unregister'(), + code:del_path(OutDir), + ok. + + +get_inh(OE_IFR,ID) -> + OE_CURRENT = orber_ifr:lookup_id(OE_IFR,ID), + INH_LIST = orber_ifr:get_base_interfaces(OE_CURRENT), + case INH_LIST of + [] -> + io:format("~nInterface ~p inherits from nobody.~n",[ID]), + []; + _ -> + print_inh_list_ids(ID, INH_LIST, []) + end. + +print_inh_list_ids(_ID, [], Acc) -> + lists:reverse(Acc); +print_inh_list_ids(ID, [H|T], Acc) -> + io:format("~n"), + Parent = orber_ifr:get_id(H), + io:format("Interface ~p inherits from ~p.~n", [ID, Parent]), + print_inh_list_ids(ID, T, [Parent|Acc]). + + + + +stdopts(OutDir) -> + [{outdir, OutDir}, {maxerrs, infinity}]. + + +compile(Dir, Files) -> + compile(Dir, Files, []). + +compile(Dir, Files, Opts) -> + {ok, Cwd} = file:get_cwd(), + file:set_cwd(Dir), + io:format("Changing to ~p~n", [Dir]), + case catch do_compile(Files, Opts) of + ok -> + file:set_cwd(Cwd); + Err -> + file:set_cwd(Cwd), + test_server:fail(Err) + end. + +do_compile([], _Opts) -> ok; +do_compile([F | Fs], Opts) -> + io:format("Compiling ~p", [F]), + case compile:file(F, Opts) of + ok -> + io:format(" ok~n", []), + do_load(F, Opts), + do_compile(Fs, Opts); + {ok, _} -> + io:format(" ok~n", []), + do_load(F, Opts), + do_compile(Fs, Opts); + {ok, _, _} -> + io:format(" ok~n", []), + do_load(F, Opts), + do_compile(Fs, Opts); + Err -> + io:format(" error: ~p~n", [Err]), + Err + end. + +do_load(File, Opts) -> + case lists:member(load, Opts) of + true -> + io:format("Loading file ~p", [File]), + code:purge(File), + R = code:load_abs(File), + io:format("Loaded: ~p", [R]); + false -> + ok + end. + + +to_list(X) when is_atom(X) -> atom_to_list(X); +to_list(X) -> X. + + + + + + + + + + + + + + + + + + diff --git a/lib/ic/test/ic_register_SUITE_data/reg_m10.idl b/lib/ic/test/ic_register_SUITE_data/reg_m10.idl new file mode 100644 index 0000000000..9c1f126b64 --- /dev/null +++ b/lib/ic/test/ic_register_SUITE_data/reg_m10.idl @@ -0,0 +1,37 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// +// IDL for testing register/unregister in the IFR when using included specs +// +#include "reg_m9.idl" + +typedef sequence<long> Sequence1; + +#include "reg_m8.idl" + +module m2 { + + interface i2 : m1::i1 + { + short op3( in long a, inout char b, out long c ); + }; + + +}; + diff --git a/lib/ic/test/ic_register_SUITE_data/reg_m11.idl b/lib/ic/test/ic_register_SUITE_data/reg_m11.idl new file mode 100644 index 0000000000..607d695357 --- /dev/null +++ b/lib/ic/test/ic_register_SUITE_data/reg_m11.idl @@ -0,0 +1,32 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// +// IDL for testing register/unregister in the IFR when using included specs +// + +module m3 { + + interface i3 + { + short op4( in long a, inout char b, out long c ); + }; + + +}; + diff --git a/lib/ic/test/ic_register_SUITE_data/reg_m12.idl b/lib/ic/test/ic_register_SUITE_data/reg_m12.idl new file mode 100644 index 0000000000..3dd9267655 --- /dev/null +++ b/lib/ic/test/ic_register_SUITE_data/reg_m12.idl @@ -0,0 +1,40 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// +// IDL for testing register/unregister in the IFR when using included specs +// Special case with multiple inheritence. +// +#include "reg_m10.idl" +#include "reg_m11.idl" + +module m4 { + + interface i4 : m2::i2 + { + short op5( in long a, inout char b, out long c ); + }; + + interface i5 : m3::i3 + { + short op6( in long a, inout char b, out long c ); + }; + + +}; + diff --git a/lib/ic/test/ic_register_SUITE_data/reg_m8.idl b/lib/ic/test/ic_register_SUITE_data/reg_m8.idl new file mode 100644 index 0000000000..dc7432c05d --- /dev/null +++ b/lib/ic/test/ic_register_SUITE_data/reg_m8.idl @@ -0,0 +1,32 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// +// IDL for testing register/unregister in the IFR when using included specs +// +module m0 { + + interface i0 { + void op1( in short c ); + float op2( in char a); + + }; + + +}; + diff --git a/lib/ic/test/ic_register_SUITE_data/reg_m9.idl b/lib/ic/test/ic_register_SUITE_data/reg_m9.idl new file mode 100644 index 0000000000..e937c41608 --- /dev/null +++ b/lib/ic/test/ic_register_SUITE_data/reg_m9.idl @@ -0,0 +1,32 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 1998-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +// +// IDL for testing register/unregister in the IFR when using included specs +// +module m1 { + + interface i1 { + void op1( in short c ); + float op2( in char a); + + }; + + +}; + diff --git a/lib/ic/test/java_client_erl_server_SUITE.erl b/lib/ic/test/java_client_erl_server_SUITE.erl new file mode 100644 index 0000000000..ee77ef0c4e --- /dev/null +++ b/lib/ic/test/java_client_erl_server_SUITE.erl @@ -0,0 +1,330 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%%---------------------------------------------------------------------- +%%% Purpose : Test suite for the backends of the IDL compiler +%%%---------------------------------------------------------------------- + +-module(java_client_erl_server_SUITE). +-include("test_server.hrl"). + + +-export([all/1,init_all/1,finish_all/1,init_per_testcase/2,fin_per_testcase/2]). +-export([marshal_ll/1,marshal_ull/1, + marshal_l/1,marshal_ul/1, + marshal_s/1,marshal_us/1, + marshal_c/1,marshal_wc/1, + marshal_str/1, + marshal_any_3/1,marshal_any_2/1]). + + +%% Top of cases + +all(doc) -> + "Test of IC with a Java-client and an Erlang generic server. " + "The communication is via Erlang distribution."; +all(suite) -> {conf,init_all,cases(),finish_all}. + +cases() -> [marshal_ll,marshal_ull, + marshal_l,marshal_ul, + marshal_s,marshal_us, + marshal_c,marshal_wc, + marshal_str, + marshal_any_3,marshal_any_2]. + +init_all(Config) when is_list(Config) -> + case case code:priv_dir(jinterface) of + {error,bad_name} -> + false; + P -> + filelib:is_dir(P) + end + of + true -> + case find_executable(["java"]) of + false -> + {skip,"Found no Java VM"}; + Path -> + [{java,Path}|Config] + end; + false -> + {skip,"No jinterface application"} + end. + + +find_executable([]) -> + false; +find_executable([E|T]) -> + case os:find_executable(E) of + false -> find_executable(T); + Path -> Path + end. + +finish_all(Config) -> Config. + + + +%% Add/remove code path and watchdog before/after each test case. +%% +init_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:add_patha(DataDir), + + %% Since other test suites use the module m_i et,al, we have + %% to make sure we are using the right modules. + code:purge(m_i), + code:purge(m_i_impl), + code:purge(oe_java_erl_test), + code:load_file(m_i), + code:load_file(m_i_impl), + code:load_file(oe_java_erl_test), + + WatchDog = test_server:timetrap(test_server:seconds(20)), + [{watchdog, WatchDog}| Config]. + +fin_per_testcase(_Case, Config) -> + DataDir = ?config(data_dir, Config), + code:del_path(DataDir), + WatchDog = ?config(watchdog, Config), + test_server:timetrap_cancel(WatchDog). + + + +%%-------------------------------------------------------------------- +%% +%% Test cases + +marshal_ll(doc) -> + ["Testing marshalling of IDL long long"]; +marshal_ll(suite) -> []; +marshal_ll(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {ok,Server} = m_i:oe_create_link([], {local,marshal_ll}), + ?line ok = java(?config(java, Config), DataDir, "JavaClient", + ["JavaClient",node(),erlang:get_cookie(),marshal_ll]), + ?line ok = m_i:stop(Server), + ok. + +marshal_ull(doc) -> + ["Testing marshalling of IDL unsigned long long"]; +marshal_ull(suite) -> []; +marshal_ull(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {ok,Server} = m_i:oe_create_link([], {local,marshal_ull}), + ?line ok = java(?config(java, Config), DataDir, "JavaClient", + ["JavaClient",node(),erlang:get_cookie(),marshal_ull]), + ?line ok = m_i:stop(Server), + ok. + +marshal_l(doc) -> + ["Testing marshalling of IDL long"]; +marshal_l(suite) -> []; +marshal_l(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {ok,Server} = m_i:oe_create_link([], {local,marshal_l}), + ?line ok = java(?config(java, Config), DataDir, "JavaClient", + ["JavaClient",node(),erlang:get_cookie(),marshal_l]), + ?line ok = m_i:stop(Server), + ok. + +marshal_ul(doc) -> + ["Testing marshalling of IDL unsigned long"]; +marshal_ul(suite) -> []; +marshal_ul(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {ok,Server} = m_i:oe_create_link([], {local,marshal_ul}), + ?line ok = java(?config(java, Config), DataDir, "JavaClient", + ["JavaClient",node(),erlang:get_cookie(),marshal_ul]), + ?line ok = m_i:stop(Server), + ok. + +marshal_s(doc) -> + ["Testing marshalling of IDL short"]; +marshal_s(suite) -> []; +marshal_s(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {ok,Server} = m_i:oe_create_link([], {local,marshal_s}), + ?line ok = java(?config(java, Config), DataDir, "JavaClient", + ["JavaClient",node(),erlang:get_cookie(),marshal_s]), + ?line ok = m_i:stop(Server), + ok. + +marshal_us(doc) -> + ["Testing marshalling of IDL unsigned short"]; +marshal_us(suite) -> []; +marshal_us(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {ok,Server} = m_i:oe_create_link([], {local,marshal_us}), + ?line ok = java(?config(java, Config), DataDir, "JavaClient", + ["JavaClient",node(),erlang:get_cookie(),marshal_us]), + ?line ok = m_i:stop(Server), + ok. + +marshal_c(doc) -> + ["Testing marshalling of IDL char"]; +marshal_c(suite) -> []; +marshal_c(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {ok,Server} = m_i:oe_create_link([], {local,marshal_c}), + ?line ok = java(?config(java, Config), DataDir, "JavaClient", + ["JavaClient",node(),erlang:get_cookie(),marshal_c]), + ?line ok = m_i:stop(Server), + ok. + +marshal_wc(doc) -> + ["Testing marshalling of IDL char"]; +marshal_wc(suite) -> []; +marshal_wc(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {ok,Server} = m_i:oe_create_link([], {local,marshal_wc}), + ?line ok = java(?config(java, Config), DataDir, "JavaClient", + ["JavaClient",node(),erlang:get_cookie(),marshal_wc]), + ?line ok = m_i:stop(Server), + ok. + +marshal_str(doc) -> + ["Testing marshalling of IDL string"]; +marshal_str(suite) -> []; +marshal_str(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {ok,Server} = m_i:oe_create_link([], {local,marshal_str}), + ?line ok = java(?config(java, Config), DataDir, +%%% "-DOtpConnection.trace=4 " + "JavaClient", + ["JavaClient",node(),erlang:get_cookie(),marshal_str]), + ?line ok = m_i:stop(Server), + ok. + +marshal_any_3(doc) -> + ["Testing marshalling of IDL any"]; +marshal_any_3(suite) -> []; +marshal_any_3(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {ok,Server} = m_i:oe_create_link([], {local,marshal_any_3}), + ?line ok = java(?config(java, Config), DataDir, "JavaClient", + ["JavaClient",node(),erlang:get_cookie(),marshal_any_3]), + ?line ok = m_i:stop(Server), + ok. + +marshal_any_2(doc) -> + ["Testing marshalling of IDL any"]; +marshal_any_2(suite) -> []; +marshal_any_2(Config) when is_list(Config) -> + ?line DataDir = ?config(data_dir, Config), + ?line {ok,Server} = m_i:oe_create_link([], {local,marshal_any_2}), + ?line ok = java(?config(java, Config), DataDir, "JavaClient", + ["JavaClient",node(),erlang:get_cookie(),marshal_any_2]), + ?line ok = m_i:stop(Server), + ok. + +%%-------------------------------------------------------------------- +%% +%% Utilities + + +java(Java, Dir, ClassAndArgs) -> + cmd(Java++" -classpath "++classpath(Dir)++" "++ClassAndArgs). + +java(Java, Dir, Class, Args) -> + java(Java, Dir, Class++" "++to_string(Args)). + +to_string([H|T]) when is_integer(H) -> + integer_to_list(H)++" "++to_string(T); +to_string([H|T]) when is_atom(H) -> + atom_to_list(H)++" "++to_string(T); +to_string([H|T]) when is_list(H) -> + lists:flatten(H)++" "++to_string(T); +to_string([]) -> []. + +% javac(Dir, File) -> +% cmd("javac -d "++Dir++" -classpath "++classpath(Dir)++" "++ +% filename:join(Dir, File)). + +classpath(Dir) -> + PS = + case os:type() of + {win32, _} -> ";"; + _ -> ":" + end, + Dir++PS++ + filename:join([code:lib_dir(ic),"priv","ic.jar"])++PS++ + filename:join([code:lib_dir(jinterface),"priv","OtpErlang.jar"])++PS++ + case os:getenv("CLASSPATH") of + false -> ""; + Classpath -> Classpath + end. + + +cmd(Cmd) -> + PortOpts = [{line,80},eof,exit_status,stderr_to_stdout], + io:format("<cmd> ~s~n", [Cmd]), + case catch open_port({spawn,Cmd}, PortOpts) of + Port when is_port(Port) -> + Result = cmd_loop(Port, []), + io:format("<cmd=~w>~n", [Result]), + case Result of + 0 -> ok; + ExitCode when is_integer(ExitCode) -> {error,ExitCode}; + Error -> Error + end; + {'EXIT',Reason} -> + {error,Reason} + end. + +cmd_loop(Port, Line) -> + receive + {Port,eof} -> + receive + {Port,{exit_status,ExitStatus}} -> + ExitStatus + after 1 -> + undefined + end; + {Port,{exit_status,ExitStatus}} -> + receive + {Port,eof} -> + ok after 1 -> ok end, + ExitStatus; + {Port,{data,{Tag,Data}}} -> + case Tag of + eol -> + io:put_chars([Line|cr_to_nl(Data)]), + io:nl(), + cmd_loop(Port, []); + noeol -> + cmd_loop(Port, [Line|cr_to_nl(Data)]) + end; + {'EXIT',Port,Reason} -> + {error,Reason}; + Other -> + io:format("WARNING: Unexpected at ~s:~p: ~p~n", + [?MODULE_STRING,?LINE,Other]), + cmd_loop(Port, Line) + end. + +%% Convert lonely CR to NL, and CRLF to NL +%% +cr_to_nl([$\r,$\n|T]) -> + [$\n|cr_to_nl(T)]; +cr_to_nl([$\r|T]) -> + [$\n|cr_to_nl(T)]; +cr_to_nl([C|T]) -> + [C|cr_to_nl(T)]; +cr_to_nl([]) -> + []. diff --git a/lib/ic/test/java_client_erl_server_SUITE_data/JavaClient.java b/lib/ic/test/java_client_erl_server_SUITE_data/JavaClient.java new file mode 100644 index 0000000000..1881279ac8 --- /dev/null +++ b/lib/ic/test/java_client_erl_server_SUITE_data/JavaClient.java @@ -0,0 +1,759 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2003-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + * + */ +public class JavaClient { + + public static void main(String[] argv) + { + System.out.println("Hello World!"); + if (argv.length < 4) { + System.out.println("Too few arguments!"); + System.exit(1); + } + // for (int j = 0; j < argv.length; j++) + // System.out.println(argv[j]); + try { + if (argv[3].equals("marshal_ll")) { + System.out.println("marshal_ll"); + marshal_ll(argv[0], argv[1], argv[2], argv[3]); + } + else if (argv[3].equals("marshal_ull")) { + marshal_ull(argv[0], argv[1], argv[2], argv[3]); + } + else if (argv[3].equals("marshal_l")) { + marshal_l(argv[0], argv[1], argv[2], argv[3]); + } + else if (argv[3].equals("marshal_ul")) { + marshal_ul(argv[0], argv[1], argv[2], argv[3]); + } + else if (argv[3].equals("marshal_s")) { + marshal_s(argv[0], argv[1], argv[2], argv[3]); + } + else if (argv[3].equals("marshal_us")) { + marshal_us(argv[0], argv[1], argv[2], argv[3]); + } + else if (argv[3].equals("marshal_c")) { + marshal_c(argv[0], argv[1], argv[2], argv[3]); + } + else if (argv[3].equals("marshal_wc")) { + marshal_wc(argv[0], argv[1], argv[2], argv[3]); + } + else if (argv[3].equals("marshal_str")) { + marshal_str(argv[0], argv[1], argv[2], argv[3]); + } + else if (argv[3].equals("marshal_any_3")) { + marshal_any_3(argv[0], argv[1], argv[2], argv[3]); + } + else if (argv[3].equals("marshal_any_2")) { + marshal_any_2(argv[0], argv[1], argv[2], argv[3]); + } + else { + System.out.println("Unknown test: "+argv[3]); + System.exit(2); + } + } catch (java.lang.Exception e) { + System.out.println("Exception!: "+e); + System.exit(3); + } + System.exit(0); + } + + + + static void marshal_ll(String selfNode, String peerNode, + String cookie, String serverName) + throws java.lang.Exception + { + m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName); + // Just warming up.. + System.out.println("Just warming up.."+i); + verify_ll(i, 3, 2, 1); + verify_ll(i, 5, 4, 3); + verify_ll(i, -128, 0, 1); + // The small integer border + verify_ll(i, 255, 0, 1); + verify_ll(i, 256, 0, 1); + // The integer border + verify_ll(i, (1L<<26)-1L, 0L, 1); + verify_ll(i, 1L<<26, 0L, 1); + verify_ll(i, -(1L<<26), 0L, 1); + verify_ll(i, (1L<<27)-1L, 0L, 1); + verify_ll(i, 1L<<27, 0L, 1); + verify_ll(i, -(1L<<27), 0L, 1); + // Bignum byte borders + verify_ll(i, (1L<<32)-1L, 0L, 1); + verify_ll(i, 1L<<32, 0L, 1); + verify_ll(i, -(1L<<32)+1L, 0L, 1); + verify_ll(i, -(1L<<32), 0L, 1); + verify_ll(i, (1L<<40)-1L, 0L, 1); + verify_ll(i, 1L<<40, 0L, 1); + verify_ll(i, -(1L<<40)+1L, 0L, 1); + verify_ll(i, -(1L<<40), 0L, 1); + verify_ll(i, (1L<<48)-1L, 0L, 1); + verify_ll(i, 1L<<48, 0L, 1); + verify_ll(i, -(1L<<48)+1L, 0L, 1); + verify_ll(i, -(1L<<48), 0L, 1); + // Java long border + verify_ll(i, java.lang.Long.MAX_VALUE, 0L, 1); + verify_ll(i, java.lang.Long.MIN_VALUE, 0L, 1); + verify_ll(i, -1L, 0L, 1); + // Impossible decodes + verify_ll_bad(i, java.lang.Long.MAX_VALUE, -1L, 1); + verify_ll_bad(i, java.lang.Long.MIN_VALUE, 1L, 1); + verify_ll_bad(i, java.lang.Long.MIN_VALUE, 0L, -1); + verify_ll_bad(i, java.lang.Long.MAX_VALUE, -1L, 2); + verify_ll_bad(i, java.lang.Long.MIN_VALUE, 0L, 2); + } + + static void marshal_ull(String selfNode, String peerNode, + String cookie, String serverName) + throws java.lang.Exception + { + m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName); + // Just warming up.. + verify_ull(i, 3, 2, 1); + verify_ull(i, 5, 4, 3); + // The small integer border + verify_ull(i, 255, 0, 1); + verify_ull(i, 256, 0, 1); + // The integer border + verify_ull(i, (1L<<26)-1L, 0L, 1); + verify_ull(i, 1L<<26, 0L, 1); + verify_ull(i, (1L<<27)-1L, 0L, 1); + verify_ull(i, 1L<<27, 0L, 1); + // Bignum byte borders + verify_ull(i, (1L<<32)-1L, 0L, 1); + verify_ull(i, 1L<<32, 0L, 1); + verify_ull(i, (1L<<40)-1L, 0L, 1); + verify_ull(i, 1L<<40, 0L, 1); + verify_ull(i, (1L<<48)-1L, 0L, 1); + verify_ull(i, 1L<<48, 0L, 1); + // Java long border + verify_ull(i, java.lang.Long.MAX_VALUE, 0L, 1); + verify_ull(i, java.lang.Long.MIN_VALUE, 0L, 1); + verify_ull(i, -1L, 0L, 1); + verify_ull(i, java.lang.Long.MAX_VALUE, + java.lang.Long.MIN_VALUE, 1); + // Impossible decodes + verify_ull_bad(i, -1L, -1L, 1); + verify_ull_bad(i, java.lang.Long.MAX_VALUE, -1L, 2); + } + + static void marshal_l(String selfNode, String peerNode, + String cookie, String serverName) + throws java.lang.Exception + { + m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName); + // Just warming up.. + verify_l(i, 3, 2, 1); + verify_l(i, 5, 4, 3); + verify_l(i, -128, 0, 1); + // The small integer border + verify_l(i, 255, 0, 1); + verify_l(i, 256, 0, 1); + // The integer border + verify_l(i, (1<<26)-1, 0, 1); + verify_l(i, 1<<26, 0, 1); + verify_l(i, -(1<<26), 0, 1); + verify_l(i, (1<<27)-1, 0, 1); + verify_l(i, 1<<27, 0, 1); + verify_l(i, -(1<<27), 0, 1); + // Java int border + verify_l(i, java.lang.Integer.MAX_VALUE, 0, 1); + verify_l(i, java.lang.Integer.MIN_VALUE, 0, 1); + // Impossible decodes + verify_l_bad(i, java.lang.Integer.MAX_VALUE, -1, 1); + verify_l_bad(i, java.lang.Integer.MIN_VALUE, 1, 1); + verify_l_bad(i, java.lang.Integer.MIN_VALUE, 0, -1); + } + + static void marshal_ul(String selfNode, String peerNode, + String cookie, String serverName) + throws java.lang.Exception + { + m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName); + // Just warming up.. + verify_ul(i, 3, 2, 1); + verify_ul(i, 5, 4, 3); + // The small integer border + verify_ul(i, 255, 0, 1); + verify_ul(i, 256, 0, 1); + // The integer border + verify_ul(i, (1<<26)-1, 0, 1); + verify_ul(i, 1<<26, 0, 1); + verify_ul(i, (1<<27)-1, 0, 1); + verify_ul(i, 1<<27, 0, 1); + // Java int border + verify_ul(i, java.lang.Integer.MAX_VALUE, 0, 1); + verify_ul(i, java.lang.Integer.MIN_VALUE, 0, 1); + verify_ul(i, -1, 0, 1); + verify_ul(i, java.lang.Integer.MAX_VALUE, + java.lang.Integer.MIN_VALUE, 1); + // Impossible decodes + verify_ul_bad(i, -1, -1, 1); + } + + static void marshal_s(String selfNode, String peerNode, + String cookie, String serverName) + throws java.lang.Exception + { + m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName); + // Just warming up.. + verify_s(i, 3, 2, 1); + verify_s(i, 5, 4, 3); + verify_s(i, -128, 0, 1); + // The small integer border + verify_s(i, 255, 0, 1); + verify_s(i, 256, 0, 1); + // Java short border + verify_s(i, java.lang.Short.MAX_VALUE, 0, 1); + verify_s(i, java.lang.Short.MIN_VALUE, 0, 1); + // Impossible decodes + verify_s_bad(i, java.lang.Short.MAX_VALUE, -1, 1); + verify_s_bad(i, java.lang.Short.MIN_VALUE, 1, 1); + verify_s_bad(i, java.lang.Short.MIN_VALUE, 0, -1); + } + + static void marshal_us(String selfNode, String peerNode, + String cookie, String serverName) + throws java.lang.Exception + { + m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName); + // Just warming up.. + verify_us(i, 3, 2, 1); + verify_us(i, 5, 4, 3); + // The small integer border + verify_us(i, 255, 0, 1); + verify_us(i, 256, 0, 1); + // Java short border + verify_us(i, java.lang.Short.MAX_VALUE, 0, 1); + verify_us(i, java.lang.Short.MIN_VALUE, 0, 1); + verify_us(i, -1, 0, 1); + verify_us(i, java.lang.Short.MAX_VALUE, + java.lang.Short.MIN_VALUE, 1); + // Impossible decodes + verify_us_bad(i, -1, -1, 1); + } + + static void marshal_c(String selfNode, String peerNode, + String cookie, String serverName) + throws java.lang.Exception + { + m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName); + // Just warming up.. + verify_c(i, '\3', '\2', 1); + verify_c(i, '\5', '\4', 3); + // The small integer border + verify_c(i, '\u00FF', '\0', 1); + verify_c(i, '\u0100', '\0', 1); + // Java char border + verify_c(i, java.lang.Character.MAX_VALUE, '\0', 1); + verify_c(i, java.lang.Character.MIN_VALUE, '\0', 1); + verify_c(i, java.lang.Character.MAX_VALUE, + java.lang.Character.MIN_VALUE, 1); + // Impossible decodes + verify_c_bad(i, '\u8000', '\0', 2); + } + + static void marshal_wc(String selfNode, String peerNode, + String cookie, String serverName) + throws java.lang.Exception + { + m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName); + // Just warming up.. + verify_wc(i, '\3', '\2', 1); + verify_wc(i, '\5', '\4', 3); + // The small integer border + verify_wc(i, '\u00FF', '\0', 1); + verify_wc(i, '\u0100', '\0', 1); + // Java char border + verify_wc(i, java.lang.Character.MAX_VALUE, '\0', 1); + verify_wc(i, java.lang.Character.MIN_VALUE, '\0', 1); + verify_wc(i, java.lang.Character.MAX_VALUE, + java.lang.Character.MIN_VALUE, 1); + // Impossible decodes + verify_c_bad(i, '\u8000', '\0', 2); + } + + static void marshal_str(String selfNode, String peerNode, + String cookie, String serverName) + throws java.lang.Exception + { + m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName); + // Just warming up.. + verify_str(i, 100, 100); + verify_str(i, 100, 1); + // Erlang string border + verify_str(i, 65535, 1); + verify_str(i, 2, 65535); + // Erlang string border out + verify_str(i, 65536, 1); + verify_str(i, 65536, 65536); + } + + static void marshal_any_3(String selfNode, String peerNode, + String cookie, String serverName) + throws java.lang.Exception + { + m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName); + com.ericsson.otp.ic.Any x = new com.ericsson.otp.ic.Any(); + com.ericsson.otp.ic.Any y = new com.ericsson.otp.ic.Any(); + com.ericsson.otp.ic.Any z = new com.ericsson.otp.ic.Any(); + + x.insert_longlong(java.lang.Long.MAX_VALUE); + y.insert_longlong(1L); + z.insert_longlong(java.lang.Long.MAX_VALUE-1L); + System.out.println("verify_any_3 longlong max"); + verify_any_3(i, x, y, 1, z); + + x.insert_longlong(java.lang.Long.MIN_VALUE); + y.insert_longlong(-1L); + z.insert_longlong(java.lang.Long.MIN_VALUE+1L); + System.out.println("verify_any_3 longlong min"); + verify_any_3(i, x, y, 1, z); + + x.insert_ulonglong(-1L); + y.insert_longlong(1L); + z.insert_ulonglong(-2L); + System.out.println("verify_any_3 ulonglong max"); + verify_any_3(i, x, y, 1, z); + + x.insert_ulonglong(0L); + y.insert_longlong(-1L); + z.insert_ulonglong(1L); + System.out.println("verify_any_3 ulonglong min"); + verify_any_3(i, x, y, 1, z); + + x.insert_long(java.lang.Integer.MAX_VALUE); + y.insert_long(1); + z.insert_long(java.lang.Integer.MAX_VALUE-1); + System.out.println("verify_any_3 long max"); + verify_any_3(i, x, y, 1, z); + + x.insert_long(java.lang.Integer.MIN_VALUE); + y.insert_long(-1); + z.insert_long(java.lang.Integer.MIN_VALUE+1); + System.out.println("verify_any_3 long min"); + verify_any_3(i, x, y, 1, z); + + x.insert_ulong(-1); + y.insert_long(1); + z.insert_ulong(-2); + System.out.println("verify_any_3 ulong max"); + verify_any_3(i, x, y, 1, z); + + x.insert_ulong(0); + y.insert_long(-1); + z.insert_ulong(1); + System.out.println("verify_any_3 ulong min"); + verify_any_3(i, x, y, 1, z); + + x.insert_short(java.lang.Short.MAX_VALUE); + y.insert_short((short)1); + z.insert_short((short)(java.lang.Short.MAX_VALUE-1)); + System.out.println("verify_any_3 short max"); + verify_any_3(i, x, y, 1, z); + + x.insert_short(java.lang.Short.MIN_VALUE); + y.insert_short((short)-1); + z.insert_short((short)(java.lang.Short.MIN_VALUE+1)); + System.out.println("verify_any_3 short min"); + verify_any_3(i, x, y, 1, z); + + x.insert_ushort((short)-1); + y.insert_short((short)1); + z.insert_ushort((short)-2); + System.out.println("verify_any_3 ushort max"); + verify_any_3(i, x, y, 1, z); + + x.insert_ushort((short)0); + y.insert_short((short)-1); + z.insert_ushort((short)1); + System.out.println("verify_any_3 ushort min"); + verify_any_3(i, x, y, 1, z); + + x.insert_char('\377'); + y.insert_char('\1'); + z.insert_char('\376'); + System.out.println("verify_any_3 char max"); + verify_any_3(i, x, y, 1, z); + + x.insert_wchar('\uFFFF'); + y.insert_wchar('\u0001'); + z.insert_wchar('\uFFFE'); + System.out.println("verify_any_3 char max"); + verify_any_3(i, x, y, 1, z); + } + + static void marshal_any_2(String selfNode, String peerNode, + String cookie, String serverName) + throws java.lang.Exception + { + m._iStub i = new m._iStub(selfNode, peerNode, cookie, serverName); + m.s s = new m.s(); + com.ericsson.otp.ic.Any a = new com.ericsson.otp.ic.Any(); + // + s.ull_x = -1L; + s.ll_x = java.lang.Long.MAX_VALUE; + s.ll_y = 1L; + s.ull_z = -2L; + s.ll_z = java.lang.Long.MAX_VALUE-1L; + // + s.ul_x = -1; + s.l_x = java.lang.Integer.MAX_VALUE; + s.l_y = 1; + s.ul_z = -2; + s.l_z = java.lang.Integer.MAX_VALUE-1; + // + s.us_x = (short)-1; + s.s_x = java.lang.Short.MAX_VALUE; + s.s_y = (short)1; + s.us_z = (short)-2; + s.s_z = (short)(java.lang.Short.MAX_VALUE-1); + // + s.c_x = '\377'; + s.c_y = '\1'; + s.c_z = '\376'; + s.wc_x = '\uFFFF'; + s.wc_y = '\u0001'; + s.wc_z = '\uFFFE'; + m.sHelper.insert(a, s); + verify_any_2(i, a, 1); + + s.ull_x = 0L; + s.ll_x = java.lang.Long.MIN_VALUE; + s.ll_y = -1L; + s.ull_z = 1L; + s.ll_z = java.lang.Long.MIN_VALUE+1L; + // + s.ul_x = 0; + s.l_x = java.lang.Integer.MIN_VALUE; + s.l_y = -1; + s.ul_z = 1; + s.l_z = java.lang.Integer.MIN_VALUE+1; + // + s.us_x = (short)0; + s.s_x = java.lang.Short.MIN_VALUE; + s.s_y = (short)-1; + s.us_z = (short)1; + s.s_z = (short)(java.lang.Short.MIN_VALUE+1); + // + s.c_x = '\0'; + s.c_y = '\0'; + s.c_z = '\0'; + s.wc_x = '\u0000'; + s.wc_y = '\u0000'; + s.wc_z = '\u0000'; + m.sHelper.insert(a, s); + verify_any_2(i, a, 1); + } + + + static void verify_ll(m._iStub i, long x, long y, int b) + throws java.lang.Exception + { + m.s a = new m.s(); + System.out.println("verify_ll "+a); + a.ll_x = x; + a.ll_y = y; + long expected = (x - y)*(short)b; + long result = i.marshal_ll(a, (short)b); + if (result == expected) { + System.out.println("verify_ll("+x+", "+y+", "+b+") => " + +result); + } else { + System.out.println("verify_ll("+x+", "+y+", "+b+") => " + +result+" != "+expected); + System.exit(4); + } + } + + static void verify_ull(m._iStub i, long x, long y, int b) + throws java.lang.Exception + { + m.s a = new m.s(); + a.ull_x = x; + a.ll_y = y; + long expected = (x - y)*(short)b; + long result = i.marshal_ull(a, (short)b); + if (result == expected) { + System.out.println("verify_ull("+x+", "+y+", "+b+") => " + +result); + } else { + System.out.println("verify_ull("+x+", "+y+", "+b+") => " + +result+" != "+expected); + System.exit(4); + } + } + + static void verify_l(m._iStub i, int x, int y, int b) + throws java.lang.Exception + { + m.s a = new m.s(); + a.l_x = x; + a.l_y = y; + int expected = (x - y)*(short)b; + int result = i.marshal_l(a, (short)b); + if (result == expected) { + System.out.println("verify_l("+x+", "+y+", "+b+") => " + +result); + } else { + System.out.println("verify_l("+x+", "+y+", "+b+") => " + +result+" != "+expected); + System.exit(4); + } + } + + static void verify_ul(m._iStub i, int x, int y, int b) + throws java.lang.Exception + { + m.s a = new m.s(); + a.ul_x = x; + a.l_y = y; + int expected = (x - y)*(short)b; + int result = i.marshal_ul(a, (short)b); + if (result == expected) { + System.out.println("verify_ul("+x+", "+y+", "+b+") => " + +result); + } else { + System.out.println("verify_ul("+x+", "+y+", "+b+") => " + +result+" != "+expected); + System.exit(4); + } + } + + static void verify_s(m._iStub i, int x, int y, int b) + throws java.lang.Exception + { + m.s a = new m.s(); + a.s_x = (short)x; + a.s_y = (short)y; + short expected = (short)((x - y)*(short)b); + short result = i.marshal_s(a, (short)b); + if (result == expected) { + System.out.println("verify_s("+x+", "+y+", "+b+") => " + +result); + } else { + System.out.println("verify_s("+x+", "+y+", "+b+") => " + +result+" != "+expected); + System.exit(4); + } + } + + static void verify_us(m._iStub i, int x, int y, int b) + throws java.lang.Exception + { + m.s a = new m.s(); + a.us_x = (short)x; + a.s_y = (short)y; + short expected = (short)((x - y)*(short)b); + short result = i.marshal_us(a, (short)b); + if (result == expected) { + System.out.println("verify_us("+x+", "+y+", "+b+") => " + +result); + } else { + System.out.println("verify_us("+x+", "+y+", "+b+") => " + +result+" != "+expected); + System.exit(4); + } + } + + static void verify_c(m._iStub i, char x, char y, int b) + throws java.lang.Exception + { + m.s a = new m.s(); + a.c_x = x; + a.c_y = y; + char expected = (char)(((int)x - (int)y)*(short)b); + char result = i.marshal_c(a, (short)b); + if (result == expected) { + System.out.println("verify_c("+x+", "+y+", "+b+") => " + +result); + } else { + System.out.println("verify_c("+x+", "+y+", "+b+") => " + +result+" != "+expected); + System.exit(4); + } + } + + static void verify_wc(m._iStub i, char x, char y, int b) + throws java.lang.Exception + { + m.s a = new m.s(); + a.wc_x = x; + a.wc_y = y; + char expected = (char)(((int)x - (int)y)*(short)b); + char result = i.marshal_wc(a, (short)b); + if (result == expected) { + System.out.println("verify_wc("+x+", "+y+", "+b+") => " + +result); + } else { + System.out.println("verify_wc("+x+", "+y+", "+b+") => " + +result+" != "+expected); + System.exit(4); + } + } + + static void verify_str(m._iStub i, int a_len, int b_len) + throws java.lang.Exception + { + String a = mk_str(a_len); + String b = mk_str(b_len); + String expected = a + b; + String result = i.strcat(a, b); + if (result.equals(expected)) { + System.out.println("verify_str(\""+a+"\", \""+b+"\") => \"" + +result+"\""); + } else { + System.out.println("verify_str(\""+a+"\", \""+b+"\") => \"" + +result+"\" != \""+expected.length()+"\""); + System.exit(4); + } + } + + static String mk_str(int len) + throws StringIndexOutOfBoundsException + { + StringBuffer s = new StringBuffer(); + // 17 characters is prime relative all bases of two - on purpose + do s.append("qwertyuiopasdfghj"); while (s.length() < len); + return s.substring(0, len); + } + + static void verify_any_3(m._iStub i, + com.ericsson.otp.ic.Any x, + com.ericsson.otp.ic.Any y, + int b, + com.ericsson.otp.ic.Any expected) + throws java.lang.Exception + { + com.ericsson.otp.ic.Any result = i.marshal_any_3(x, y, (short)b); + if (! expected.equal(result)) { + System.exit(4); + } + } + + static void verify_any_2(m._iStub i, com.ericsson.otp.ic.Any a, int b) + throws java.lang.Exception + { + com.ericsson.otp.ic.Any result = i.marshal_any_2(a, (short)b); + if (! a.equal(result)) { + System.exit(4); + } + } + + + + static void verify_ll_bad(m._iStub i, long x, long y, int b) + throws java.lang.Exception + { + try { + verify_ll(i, x, y, b); + System.out.println("Expected exception missing!"); + System.exit(5); + } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) { + System.out.println("Expected exception: "+e); + } + } + + static void verify_ull_bad(m._iStub i, long x, long y, int b) + throws java.lang.Exception + { + try { + verify_ull(i, x, y, b); + System.out.println("Expected exception missing!"); + System.exit(5); + } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) { + System.out.println("Expected exception: "+e); + } + } + + static void verify_l_bad(m._iStub i, int x, int y, int b) + throws java.lang.Exception + { + try { + verify_l(i, x, y, b); + System.out.println("Expected exception missing!"); + System.exit(5); + } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) { + System.out.println("Expected exception: "+e); + } + } + + static void verify_ul_bad(m._iStub i, int x, int y, int b) + throws java.lang.Exception + { + try { + verify_ul(i, x, y, b); + System.out.println("Expected exception missing!"); + System.exit(5); + } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) { + System.out.println("Expected exception: "+e); + } + } + + static void verify_s_bad(m._iStub i, int x, int y, int b) + throws java.lang.Exception + { + try { + verify_s(i, x, y, b); + System.out.println("Expected exception missing!"); + System.exit(5); + } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) { + System.out.println("Expected exception: "+e); + } + } + + static void verify_us_bad(m._iStub i, int x, int y, int b) + throws java.lang.Exception + { + try { + verify_us(i, x, y, b); + System.out.println("Expected exception missing!"); + System.exit(5); + } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) { + System.out.println("Expected exception: "+e); + } + } + + static void verify_c_bad(m._iStub i, char x, char y, int b) + throws java.lang.Exception + { + try { + verify_c(i, x, y, b); + System.out.println("Expected exception missing!"); + System.exit(5); + } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) { + System.out.println("Expected exception: "+e); + } + } + + static void verify_wc_bad(m._iStub i, char x, char y, int b) + throws java.lang.Exception + { + try { + verify_wc(i, x, y, b); + System.out.println("Expected exception missing!"); + System.exit(5); + } catch (com.ericsson.otp.erlang.OtpErlangDecodeException e) { + System.out.println("Expected exception: "+e); + } + } + +} diff --git a/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src b/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src new file mode 100644 index 0000000000..de1503401c --- /dev/null +++ b/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src @@ -0,0 +1,88 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# +# Makefile.src for java_client_erl_server test +# Note: This file *must* work for both Unix and Windows +# +# We use both `rm' (Unix) and `del' (Windows) for removing files, but +# with a `-' in front so that the error in not finding `rm' (`del') on +# Windows (Unix) is ignored. +# +# VxWorks? XXX +# + +.SUFFIXES: +.SUFFIXES: .erl .idl .@EMULATOR@ .java + + +JAVAC = @JAVAC@ +ERLC = erlc + +# ic variables available from ts: +# +# ic_libpath: @ic_libpath@ +# ic_include_path: @ic_include_path@ + +IC_INCLUDE_PATH = @ic_include_path@ +IC_CLASSPATH = @ic_classpath@ + +JINTERFACE_CLASSPATH = @jinterface_classpath@ + +CLASSPATH = .@PS@$(IC_CLASSPATH)@PS@$(JINTERFACE_CLASSPATH)@PS@ + +GEN_JAVA_FILES = \ + m@DS@_iImplBase.java \ + m@DS@_iStub.java \ + m@DS@i.java m@DS@iHelper.java m@DS@iHolder.java \ + m@DS@s.java m@DS@sHelper.java m@DS@sHolder.java + +GEN_HRL_FILES = \ + m.hrl \ + m_i.hrl \ + oe_java_erl_test.hrl + +GEN_ERL_FILES = \ + m_i.erl \ + oe_java_erl_test.erl + +JAVA_FILES = $(GEN_JAVA_FILES) JavaClient.java +CLASS_FILES = $(JAVA_FILES:.java=.class) +ERL_FILES = $(GEN_ERL_FILES) m_i_impl.erl +EBINS = $(ERL_FILES:.erl=.@EMULATOR@) + + +all: $(CLASS_FILES) $(EBINS) + +clean: + -rm -f $(GEN_JAVA_FILES) $(CLASS_FILES) \ + $(GEN_ERL_FILES) $(GEN_HRL_FILES) $(EBINS) + -del /F /Q $(GEN_JAVA_FILES) $(CLASS_FILES) \ + $(GEN_ERL_FILES) $(GEN_HRL_FILES) $(EBINS) + +$(GEN_JAVA_FILES) : java_erl_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,java}" java_erl_test.idl + +$(CLASS_FILES) : $(JAVA_FILES) + $(JAVAC) -classpath $(CLASSPATH) $(JAVA_FILES) + +$(GEN_ERL_FILES) $(GEN_HRL_FILES): java_erl_test.idl + $(ERLC) -I $(IC_INCLUDE_PATH) "+{be,erl_genserv}" java_erl_test.idl + +.erl.@EMULATOR@: + $(ERLC) -I $(IC_INCLUDE_PATH) $< diff --git a/lib/ic/test/java_client_erl_server_SUITE_data/java_erl_test.idl b/lib/ic/test/java_client_erl_server_SUITE_data/java_erl_test.idl new file mode 100644 index 0000000000..b72c972d3b --- /dev/null +++ b/lib/ic/test/java_client_erl_server_SUITE_data/java_erl_test.idl @@ -0,0 +1,68 @@ + + +// %CopyrightBegin% +// +// Copyright Ericsson AB 2003-2010. All Rights Reserved. +// +// The contents of this file are subject to the Erlang Public License, +// Version 1.1, (the "License"); you may not use this file except in +// compliance with the License. You should have received a copy of the +// Erlang Public License along with this software. If not, it can be +// retrieved online at http://www.erlang.org/. +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +// the License for the specific language governing rights and limitations +// under the License. +// +// %CopyrightEnd% +module m { + + struct s { + long long ll_x; + unsigned long long ull_x; + long long ll_y; + long long ll_z; + unsigned long long ull_z; + + long l_x; + unsigned long ul_x; + long l_y; + long l_z; + unsigned long ul_z; + + short s_x; + unsigned short us_x; + short s_y; + short s_z; + unsigned short us_z; + + char c_x; + char c_y; + char c_z; + + wchar wc_x; + wchar wc_y; + wchar wc_z; + }; + + interface i { + long long marshal_ll( in s a, in short b ); + unsigned long long marshal_ull( in s a, in short b ); + + long marshal_l( in s a, in short b ); + unsigned long marshal_ul( in s a, in short b ); + + short marshal_s( in s a, in short b ); + unsigned short marshal_us( in s a, in short b ); + + char marshal_c( in s a, in short b ); + wchar marshal_wc( in s a, in short b ); + + string strcat( in string a, in string b ); + + any marshal_any_3( in any x, in any y, in short b ); + any marshal_any_2( in any a, in short b ); + }; + +}; diff --git a/lib/ic/test/java_client_erl_server_SUITE_data/m_i_impl.erl b/lib/ic/test/java_client_erl_server_SUITE_data/m_i_impl.erl new file mode 100644 index 0000000000..77e532288f --- /dev/null +++ b/lib/ic/test/java_client_erl_server_SUITE_data/m_i_impl.erl @@ -0,0 +1,169 @@ +%%-------------------------------------------------------------------- +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2003-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%-------------------------------------------------------------------- +-module(m_i_impl). + +-export([marshal_ll/3,marshal_ull/3, + marshal_l/3,marshal_ul/3, + marshal_s/3,marshal_us/3, + marshal_c/3,marshal_wc/3, + strcat/3, + marshal_any_3/4,marshal_any_2/3]). +-export([init/1,terminate/2,code_change/3]). + +-include("m.hrl"). + +-define(TK_M_S, {tk_struct, + "IDL:m/s:1.0", + "s", + [{"ll_x",tk_longlong}, + {"ull_x",tk_ulonglong}, + {"ll_y",tk_longlong}, + {"ll_z",tk_longlong}, + {"ull_z",tk_ulonglong}, + {"l_x",tk_long}, + {"ul_x",tk_ulong}, + {"l_y",tk_long}, + {"l_z",tk_long}, + {"ul_z",tk_ulong}, + {"s_x",tk_short}, + {"us_x",tk_ushort}, + {"s_y",tk_short}, + {"s_z",tk_short}, + {"us_z",tk_ushort}, + {"c_x",tk_char}, + {"c_y",tk_char}, + {"c_z",tk_char}, + {"wc_x",tk_wchar}, + {"wc_y",tk_wchar}, + {"wc_z",tk_wchar}|_]}). + + + +marshal_ll(State, #m_s{ll_x = X, ll_y = Y}=_A, B) when integer(B) -> + R = (X - Y)*B, + io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]), + {reply, R, State}. + +marshal_ull(State, #m_s{ull_x = X, ll_y = Y}=_A, B) when integer(B) -> + R = (X - Y)*B, + io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]), + {reply, R, State}. + + +marshal_l(State, #m_s{l_x = X, l_y = Y}=_A, B) when integer(B) -> + R = (X - Y)*B, + io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]), + {reply, R, State}. + +marshal_ul(State, #m_s{ul_x = X, l_y = Y}=_A, B) when integer(B) -> + R = (X - Y)*B, + io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]), + {reply, R, State}. + + +marshal_s(State, #m_s{s_x = X, s_y = Y}=_A, B) when integer(B) -> + R = (X - Y)*B, + io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]), + {reply, R, State}. + +marshal_us(State, #m_s{us_x = X, s_y = Y}=_A, B) when integer(B) -> + R = (X - Y)*B, + io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]), + {reply, R, State}. + + +marshal_c(State, #m_s{c_x = X, c_y = Y}=_A, B) when integer(B) -> + R = (X - Y)*B, + io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]), + {reply, R, State}. + +marshal_wc(State, #m_s{wc_x = X, wc_y = Y}=_A, B) when integer(B) -> + R = (X - Y)*B, + io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]), + {reply, R, State}. + +strcat(State, A, B) when list(A), list(B) -> + R = A++B, + io:format("~p", [{?MODULE,?LINE,[length(A),length(B),A,B,R]}]), + {reply, R, State}; +strcat(State, A, B) -> + io:format("~p", [{?MODULE,?LINE,[A,B]}]), + {reply, [], State}. + +marshal_any_3(State, {any,TkX,_}=X, {any,_,_}=Y, B) when integer(B) -> + R = any(mul(sub(any(X), any(Y)), B), TkX), + io:format("~p", [{?MODULE,?LINE,[X,Y,B,R]}]), + {reply, R, State}. + +marshal_any_2(State, + {any,TkA,#m_s{ll_x=LL_X, ull_x=ULL_X, ll_y=LL_Y, + l_x=L_X, ul_x=UL_X, l_y=L_Y, + s_x=S_X, us_x=US_X, s_y=S_Y, + c_x=C_X, c_y=C_Y, + wc_x=WC_X, wc_y=WC_Y} = A}, + B) when integer(B) -> + {check_type_code,?TK_M_S} = {check_type_code,TkA}, + ULL_Z = (ULL_X - LL_Y) * B, + LL_Z = (LL_X - LL_Y) * B, + UL_Z = (UL_X - L_Y) * B, + L_Z = (L_X - L_Y) * B, + US_Z = (US_X - S_Y) * B, + S_Z = (S_X - S_Y) * B, + C_Z = (C_X - C_Y) * B, + WC_Z = (WC_X - WC_Y) * B, + R = A#m_s{ll_z=LL_Z, ull_z=ULL_Z, + l_z=L_Z, ul_z=UL_Z, + s_z=S_Z, us_z=US_Z, + c_z=C_Z, wc_z=WC_Z}, + io:format("~p", [{?MODULE,?LINE,[A,B,R]}]), + {reply, {any,TkA,R}, State}. + + + +init(_Env) -> + {ok, []}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + + +any({any,tk_longlong,X}) -> X; +any({any,tk_long,X}) -> X; +any({any,tk_short,X}) -> X; +any({any,tk_ulonglong,X}) -> X; +any({any,tk_ulong,X}) -> X; +any({any,tk_ushort,X}) -> X; +any({any,tk_char,X}) -> X; +any({any,tk_wchar,X}) -> X. + +any(X, Tk) when integer(X) -> {any,Tk,X}. + +sub(X, Y) when integer(X), integer(Y) -> + X - Y. + +mul(X, Y) when integer(X), integer(Y) -> + X * Y. + +napp(0, L) -> L; +napp(N, L) when integer(N), N >= 1 -> napp(N-1, L)++L. diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml index 032dcc5251..8e7192a496 100644 --- a/lib/kernel/doc/src/gen_tcp.xml +++ b/lib/kernel/doc/src/gen_tcp.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -284,9 +284,10 @@ socket() <type> <v>Socket = socket()</v> <v>Length = int()</v> - <v>Packet = [char()] | binary()</v> + <v>Packet = [char()] | binary() | HttpPacket</v> <v>Timeout = int() | infinity</v> <v>Reason = closed | posix()</v> + <v>HttpPacket = see the description of <c>HttpPacket</c> in <seealso marker="erts:erlang#decode_packet/3">erlang:decode_packet/3</seealso></v> </type> <desc> <p>This function receives a packet from a socket in passive diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index a1542ab507..cccfa75005 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -39,7 +39,7 @@ open() -> open([]). open(Opts) when is_list(Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), case Mod:open(Opts) of {error,badarg} -> erlang:error(badarg, [Opts]); @@ -234,17 +234,27 @@ controlling_process(S, Pid) -> %% Utilites %% -%% Get the SCTP moudule -mod() -> inet_db:sctp_module(). +%% Get the SCTP module, but IPv6 address overrides default IPv4 +mod(Address) -> + case inet_db:sctp_module() of + inet_sctp when tuple_size(Address) =:= 8 -> + inet6_sctp; + Mod -> + Mod + end. %% Get the SCTP module, but option sctp_module|inet|inet6 overrides -mod([{sctp_module,Mod}|_]) -> +mod([{sctp_module,Mod}|_], _Address) -> Mod; -mod([inet|_]) -> +mod([inet|_], _Address) -> inet_sctp; -mod([inet6|_]) -> +mod([inet6|_], _Address) -> inet6_sctp; -mod([_|Opts]) -> - mod(Opts); -mod([]) -> - mod(). +mod([{ip, Address}|Opts], _) -> + mod(Opts, Address); +mod([{ifaddr, Address}|Opts], _) -> + mod(Opts, Address); +mod([_|Opts], Address) -> + mod(Opts, Address); +mod([], Address) -> + mod(Address). diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index 7401b06a64..16a87d71b6 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -46,7 +46,7 @@ connect(Address, Port, Opts, Time) -> end. connect1(Address,Port,Opts,Timer) -> - Mod = mod(Opts), + Mod = mod(Opts, Address), case Mod:getaddrs(Address,Timer) of {ok,IPs} -> case Mod:getserv(Port) of @@ -73,7 +73,7 @@ try_connect([], _Port, _Opts, _Timer, _Mod, Err) -> %% Listen on a tcp port %% listen(Port, Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), case Mod:getserv(Port) of {ok,TP} -> Mod:listen(TP, Opts); @@ -173,20 +173,30 @@ controlling_process(S, NewOwner) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), Mod:fdopen(Fd, Opts). -%% Get the tcp_module -mod() -> inet_db:tcp_module(). +%% Get the tcp_module, but IPv6 address overrides default IPv4 +mod(Address) -> + case inet_db:tcp_module() of + inet_tcp when tuple_size(Address) =:= 8 -> + inet6_tcp; + Mod -> + Mod + end. %% Get the tcp_module, but option tcp_module|inet|inet6 overrides -mod([{tcp_module,Mod}|_]) -> +mod([{tcp_module,Mod}|_], _Address) -> Mod; -mod([inet|_]) -> +mod([inet|_], _Address) -> inet_tcp; -mod([inet6|_]) -> +mod([inet6|_], _Address) -> inet6_tcp; -mod([_|Opts]) -> - mod(Opts); -mod([]) -> - mod(). +mod([{ip, Address}|Opts], _) -> + mod(Opts, Address); +mod([{ifaddr, Address}|Opts], _) -> + mod(Opts, Address); +mod([_|Opts], Address) -> + mod(Opts, Address); +mod([], Address) -> + mod(Address). diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl index 6bded4bda6..99020c7b6c 100644 --- a/lib/kernel/src/gen_udp.erl +++ b/lib/kernel/src/gen_udp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -29,7 +29,7 @@ open(Port) -> open(Port, []). open(Port, Opts) -> - Mod = mod(Opts), + Mod = mod(Opts, undefined), {ok,UP} = Mod:getserv(Port), Mod:open(UP, Opts). @@ -97,21 +97,31 @@ controlling_process(S, NewOwner) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - Mod = mod(), + Mod = mod(Opts, undefined), Mod:fdopen(Fd, Opts). -%% Get the udp_module -mod() -> inet_db:udp_module(). +%% Get the udp_module, but IPv6 address overrides default IPv4 +mod(Address) -> + case inet_db:udp_module() of + inet_udp when tuple_size(Address) =:= 8 -> + inet6_udp; + Mod -> + Mod + end. %% Get the udp_module, but option udp_module|inet|inet6 overrides -mod([{udp_module,Mod}|_]) -> +mod([{udp_module,Mod}|_], _Address) -> Mod; -mod([inet|_]) -> +mod([inet|_], _Address) -> inet_udp; -mod([inet6|_]) -> +mod([inet6|_], _Address) -> inet6_udp; -mod([_|Opts]) -> - mod(Opts); -mod([]) -> - mod(). +mod([{ip, Address}|Opts], _) -> + mod(Opts, Address); +mod([{ifaddr, Address}|Opts], _) -> + mod(Opts, Address); +mod([_|Opts], Address) -> + mod(Opts, Address); +mod([], Address) -> + mod(Address). diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index eb06d4324b..9aa94a0868 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -27,12 +27,12 @@ -export( [basic/1, api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1, - xfer_min/1,xfer_active/1,def_sndrcvinfo/1]). + xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1]). all(suite) -> [basic, api_open_close,api_listen,api_connect_init,api_opts, - xfer_min,xfer_active,def_sndrcvinfo]. + xfer_min,xfer_active,def_sndrcvinfo,implicit_inet6]. init_per_testcase(_Func, Config) -> Dog = test_server:timetrap(test_server:seconds(15)), @@ -551,3 +551,58 @@ api_opts(Config) when is_list(Config) -> {{error,einval},{unix,sunos}} -> ok end. + +implicit_inet6(Config) when is_list(Config) -> + ?line Hostname = ok(inet:gethostname()), + ?line + case gen_sctp:open(0, [inet6]) of + {ok,S1} -> + ?line + case inet:getaddr(Hostname, inet6) of + {ok,Host} -> + ?line Loopback = {0,0,0,0,0,0,0,1}, + ?line io:format("~s ~p~n", ["Loopback",Loopback]), + ?line implicit_inet6(S1, Loopback), + ?line ok = gen_sctp:close(S1), + %% + ?line Localhost = + ok(inet:getaddr("localhost", inet6)), + ?line io:format("~s ~p~n", ["localhost",Localhost]), + ?line S2 = + ok(gen_sctp:open(0, [{ip,Localhost}])), + ?line implicit_inet6(S2, Localhost), + ?line ok = gen_sctp:close(S2), + %% + ?line io:format("~s ~p~n", [Hostname,Host]), + ?line S3 = + ok(gen_sctp:open(0, [{ifaddr,Host}])), + ?line implicit_inet6(S3, Host), + ?line ok = gen_sctp:close(S1); + {error,eafnosupport} -> + ?line ok = gen_sctp:close(S1), + {skip,"Can not look up IPv6 address"} + end; + _ -> + {skip,"IPv6 not supported"} + end. + +implicit_inet6(S1, Addr) -> + ?line ok = gen_sctp:listen(S1, true), + ?line P1 = ok(inet:port(S1)), + ?line S2 = ok(gen_sctp:open(0, [inet6])), + ?line P2 = ok(inet:port(S2)), + ?line #sctp_assoc_change{state=comm_up} = + ok(gen_sctp:connect(S2, Addr, P1, [])), + ?line case ok(gen_sctp:recv(S1)) of + {Addr,P2,[],#sctp_assoc_change{state=comm_up}} -> + ok + end, + ?line case ok(inet:sockname(S1)) of + {Addr,P1} -> ok; + {{0,0,0,0,0,0,0,0},P1} -> ok + end, + ?line case ok(inet:sockname(S2)) of + {Addr,P2} -> ok; + {{0,0,0,0,0,0,0,0},P2} -> ok + end, + ?line ok = gen_sctp:close(S2). diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index 11d19aaa82..94637290a1 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,10 +30,11 @@ t_connect/1, t_connect_bad/1, t_recv/1, t_recv_timeout/1, t_recv_eof/1, t_shutdown_write/1, t_shutdown_both/1, t_shutdown_error/1, - t_fdopen/1]). + t_fdopen/1, t_implicit_inet6/1]). all(suite) -> [t_accept, t_connect, t_recv, t_shutdown_write, - t_shutdown_both, t_shutdown_error, t_fdopen]. + t_shutdown_both, t_shutdown_error, t_fdopen, + t_implicit_inet6]. init_per_testcase(_Func, Config) -> Dog = test_server:timetrap(test_server:seconds(60)), @@ -156,6 +157,54 @@ t_fdopen(Config) when is_list(Config) -> ok. +%%% implicit inet6 option to api functions + +t_implicit_inet6(Config) when is_list(Config) -> + ?line Hostname = ok(inet:gethostname()), + ?line + case gen_tcp:listen(0, [inet6]) of + {ok,S1} -> + ?line + case inet:getaddr(Hostname, inet6) of + {ok,Host} -> + ?line Loopback = {0,0,0,0,0,0,0,1}, + ?line io:format("~s ~p~n", ["Loopback",Loopback]), + ?line implicit_inet6(S1, Loopback), + ?line ok = gen_tcp:close(S1), + %% + ?line Localhost = + ok(inet:getaddr("localhost", inet6)), + ?line io:format("~s ~p~n", ["localhost",Localhost]), + ?line S2 = ok(gen_tcp:listen(0, [{ip,Localhost}])), + ?line implicit_inet6(S2, Localhost), + ?line ok = gen_tcp:close(S2), + %% + ?line io:format("~s ~p~n", [Hostname,Host]), + ?line S3 = ok(gen_tcp:listen(0, [{ifaddr,Host}])), + ?line implicit_inet6(S3, Host), + ?line ok = gen_tcp:close(S1); + {error,eafnosupport} -> + ?line ok = gen_tcp:close(S1), + {skip,"Can not look up IPv6 address"} + end; + _ -> + {skip,"IPv6 not supported"} + end. + +implicit_inet6(S, Addr) -> + ?line P = ok(inet:port(S)), + ?line S2 = ok(gen_tcp:connect(Addr, P, [])), + ?line P2 = ok(inet:port(S2)), + ?line S1 = ok(gen_tcp:accept(S)), + ?line P1 = P = ok(inet:port(S1)), + ?line {Addr,P2} = ok(inet:peername(S1)), + ?line {Addr,P1} = ok(inet:peername(S2)), + ?line {Addr,P1} = ok(inet:sockname(S1)), + ?line {Addr,P2} = ok(inet:sockname(S2)), + ?line ok = gen_tcp:close(S2), + ?line ok = gen_tcp:close(S1). + + %%% Utilities @@ -217,3 +266,5 @@ unused_ip(A, B, C, D) -> {ok, _} -> unused_ip(A, B, C, D+1); {error, _} -> {ok, {A, B, C, D}} end. + +ok({ok,V}) -> V. diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 5d726a3b1b..d73c5fab56 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% -module(gen_tcp_misc_SUITE). @@ -957,12 +957,11 @@ http_bad_packet(Config) when is_list(Config) -> http_worker(S) -> case gen_tcp:recv(S, 0, 30000) of + {ok,{http_error,Error}} -> + io:format("Http error: ~s\n", [Error]); {ok,Data} -> io:format("Data: ~p\n", [Data]), - http_worker(S); - {error,Rsn} -> - io:format("Error: ~p\n", [Rsn]), - ok + http_worker(S) end. http_bad_client(Port) -> diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index fa1991872b..44dd8607b9 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% Copyright Ericsson AB 1998-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -34,12 +34,12 @@ -export([send_to_closed/1, buffer_size/1, binary_passive_recv/1, bad_address/1, - read_packets/1, open_fd/1, connect/1]). + read_packets/1, open_fd/1, connect/1, implicit_inet6/1]). all(suite) -> [send_to_closed, buffer_size, binary_passive_recv, bad_address, read_packets, - open_fd, connect]. + open_fd, connect, implicit_inet6]. init_per_testcase(_Case, Config) -> ?line Dog=test_server:timetrap(?default_timeout), @@ -425,3 +425,57 @@ connect(Config) when is_list(Config) -> ok = gen_udp:send(S2, <<16#deadbeef:32>>), {error,econnrefused} = gen_udp:recv(S2, 0, 5), ok. + +implicit_inet6(Config) when is_list(Config) -> + ?line Hostname = ok(inet:gethostname()), + ?line Active = {active,false}, + ?line + case gen_udp:open(0, [inet6,Active]) of + {ok,S1} -> + ?line + case inet:getaddr(Hostname, inet6) of + {ok,Host} -> + ?line Loopback = {0,0,0,0,0,0,0,1}, + ?line io:format("~s ~p~n", ["Loopback",Loopback]), + ?line implicit_inet6(S1, Active, Loopback), + ?line ok = gen_udp:close(S1), + %% + ?line Localhost = + ok(inet:getaddr("localhost", inet6)), + ?line io:format("~s ~p~n", ["localhost",Localhost]), + ?line S2 = + ok(gen_udp:open(0, [{ip,Localhost},Active])), + ?line implicit_inet6(S2, Active, Localhost), + ?line ok = gen_udp:close(S2), + %% + ?line io:format("~s ~p~n", [Hostname,Host]), + ?line S3 = + ok(gen_udp:open(0, [{ifaddr,Host},Active])), + ?line implicit_inet6(S3, Active, Host), + ?line ok = gen_udp:close(S1); + {error,eafnosupport} -> + ?line ok = gen_udp:close(S1), + {skip,"Can not look up IPv6 address"} + end; + _ -> + {skip,"IPv6 not supported"} + end. + +implicit_inet6(S1, Active, Addr) -> + ?line P1 = ok(inet:port(S1)), + ?line S2 = ok(gen_udp:open(0, [inet6,Active])), + ?line P2 = ok(inet:port(S2)), + ?line ok = gen_udp:connect(S2, Addr, P1), + ?line ok = gen_udp:connect(S1, Addr, P2), + ?line {Addr,P2} = ok(inet:peername(S1)), + ?line {Addr,P1} = ok(inet:peername(S2)), + ?line {Addr,P1} = ok(inet:sockname(S1)), + ?line {Addr,P2} = ok(inet:sockname(S2)), + ?line ok = gen_udp:send(S1, Addr, P2, "ping"), + ?line {Addr,P1,"ping"} = ok(gen_udp:recv(S2, 1024, 1000)), + ?line ok = gen_udp:send(S2, Addr, P1, "pong"), + ?line {Addr,P2,"pong"} = ok(gen_udp:recv(S1, 1024)), + ?line ok = gen_udp:close(S2). + + +ok({ok,V}) -> V. diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index eb8f918491..f4f27933a5 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -26,7 +26,8 @@ t_gethostbyaddr_v6/1, t_getaddr_v6/1, t_gethostbyname_v6/1, ipv4_to_ipv6/1, host_and_addr/1, parse/1, t_gethostnative/1, gethostnative_parallell/1, cname_loop/1, - gethostnative_soft_restart/1,gethostnative_debug_level/1,getif/1]). + gethostnative_soft_restart/1,gethostnative_debug_level/1,getif/1, + getif_ifr_name_overflow/1,getservbyname_overflow/1]). -export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1, kill_gethost/0, parallell_gethost/0]). @@ -39,7 +40,7 @@ all(suite) -> ipv4_to_ipv6, host_and_addr, parse,t_gethostnative, gethostnative_parallell, cname_loop, gethostnative_debug_level,gethostnative_soft_restart, - getif]. + getif,getif_ifr_name_overflow,getservbyname_overflow]. init_per_testcase(_Func, Config) -> Dog = test_server:timetrap(test_server:seconds(60)), @@ -876,6 +877,17 @@ getif(Config) when is_list(Config) -> ?line {ok,Address} = inet:getaddr(Hostname, inet), ?line {ok,Loopback} = inet:getaddr("localhost", inet), ?line {ok,Interfaces} = inet:getiflist(), + ?line HWAs = + lists:sort( + lists:foldl( + fun (I, Acc) -> + case inet:ifget(I, [hwaddr]) of + {ok,[{hwaddr,A}]} -> [A|Acc]; + {ok,[]} -> Acc + end + end, [], Interfaces)), + ?line io:format("HWAs = ~p~n", [HWAs]), + ?line length(HWAs) > 0 orelse ?t:fail(no_HWAs), ?line Addresses = lists:sort( lists:foldl( @@ -891,6 +903,20 @@ getif(Config) when is_list(Config) -> ?line true = ip_member(Loopback, Addresses), ?line ok. +getif_ifr_name_overflow(doc) -> + "Test long interface names do not overrun buffer"; +getif_ifr_name_overflow(Config) when is_list(Config) -> + %% emulator should not crash + ?line {ok,[]} = inet:ifget(lists:duplicate(128, "x"), [addr]), + ok. + +getservbyname_overflow(doc) -> + "Test long service names do not overrun buffer"; +getservbyname_overflow(Config) when is_list(Config) -> + %% emulator should not crash + ?line {error,einval} = inet:getservbyname(list_to_atom(lists:flatten(lists:duplicate(128, "x"))), tcp), + ok. + %% Works just like lists:member/2, except that any {127,_,_,_} tuple %% matches any other {127,_,_,_}. We do this to handle Linux systems %% that use (for instance) 127.0.1.1 as the IP address for the hostname. diff --git a/lib/mnesia/test/Makefile b/lib/mnesia/test/Makefile index a4f32e3f78..4f98efaed1 100644 --- a/lib/mnesia/test/Makefile +++ b/lib/mnesia/test/Makefile @@ -109,7 +109,7 @@ release_spec: opt release_tests_spec: opt $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) mnesia.spec mnesia.spec.vxworks $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR) - $(INSTALL_PROGRAM) mt $(INSTALL_PROGS) $(RELSYSDIR) + $(INSTALL_SCRIPT) mt $(INSTALL_PROGS) $(RELSYSDIR) # chmod -f -R u+w $(RELSYSDIR) # @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) diff --git a/lib/os_mon/test/Makefile b/lib/os_mon/test/Makefile new file mode 100644 index 0000000000..c87285e38b --- /dev/null +++ b/lib/os_mon/test/Makefile @@ -0,0 +1,92 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2010. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk + +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES= \ + os_mon_SUITE \ + disksup_SUITE \ + memsup_SUITE \ + cpu_sup_SUITE \ + os_mon_mib_SUITE \ + os_sup_SUITE \ + os_mon_conf + +EBIN = . + +HRL_FILES= + +ERL_FILES= $(MODULES:%=%.erl) + +TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +SOURCE = $(ERL_FILES) $(HRL_FILES) + +EMAKEFILE=Emakefile + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/os_mon_test + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +ERL_MAKE_FLAGS += +ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include \ + -I$(ERL_TOP)/lib/snmp/include + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +make_emakefile: + $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\ + > $(EMAKEFILE) + +tests debug opt: make_emakefile + erl $(ERL_MAKE_FLAGS) -make + +clean: + rm -f $(EMAKEFILE) + rm -f $(TARGET_FILES) + rm -f core *~ + +docs: + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: + +release_tests_spec: make_emakefile + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) os_mon.spec $(EMAKEFILE) $(SOURCE) $(RELSYSDIR) + +## tar chf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) + +release_docs_spec: diff --git a/lib/os_mon/test/cpu_sup_SUITE.erl b/lib/os_mon/test/cpu_sup_SUITE.erl new file mode 100644 index 0000000000..45f9d981d1 --- /dev/null +++ b/lib/os_mon/test/cpu_sup_SUITE.erl @@ -0,0 +1,282 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(cpu_sup_SUITE). +-include("test_server.hrl"). + +%% Test server specific exports +-export([all/1]). +-export([init_per_suite/1, end_per_suite/1]). +-export([init_per_testcase/2, end_per_testcase/2]). + +%% Test cases +-export([load_api/1]). +-export([util_api/1, util_values/1]). +-export([port/1]). +-export([terminate/1, unavailable/1, restart/1]). + +%% Default timetrap timeout (set in init_per_testcase) +-define(default_timeout, ?t:minutes(1)). + +init_per_suite(Config) when is_list(Config) -> + ?line ok = application:start(os_mon), + Config. + +end_per_suite(Config) when is_list(Config) -> + ?line ok = application:stop(os_mon), + Config. + +init_per_testcase(_Case, Config) -> + Dog = ?t:timetrap(?default_timeout), + [{watchdog, Dog} | Config]. + +end_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +all(suite) -> + case ?t:os_type() of + {unix, sunos} -> + [load_api, util_api, util_values, port, + {conf, terminate, [unavailable], restart}]; + {unix, linux} -> + [load_api, util_api, util_values, port, + {conf, terminate, [unavailable], restart}]; + {unix, _OSname} -> + [load_api]; + _OS -> + [unavailable] + end. + +load_api(suite) -> + []; +load_api(doc) -> + ["Test of load API functions"]; +load_api(Config) when is_list(Config) -> + + %% nprocs() + ?line N = cpu_sup:nprocs(), + ?line true = is_integer(N), + ?line true = N>0, + + %% avg1() + ?line Load1 = cpu_sup:avg1(), + ?line true = is_integer(Load1), + ?line true = Load1>0, + + %% avg5() + ?line Load5 = cpu_sup:avg5(), + ?line true = is_integer(Load5), + ?line true = Load5>0, + + %% avg15() + ?line Load15 = cpu_sup:avg15(), + ?line true = is_integer(Load15), + ?line true = Load15>0, + + ok. + +util_api(suite) -> + []; +util_api(doc) -> + ["Test of utilization API functions"]; +util_api(Config) when is_list(Config) -> + %% Some useful funs when testing util/1 + BusyP = fun({user, _Share}) -> true; + ({nice_user, _Share}) -> true; + ({kernel, _Share}) -> true; + ({hard_irq, _Share}) -> true; + ({soft_irq, _Share}) -> true; + (_) -> false + end, + NonBusyP = fun({wait, _Share}) -> true; + ({idle, _Share}) -> true; + ({steal, _Share}) -> true; + (_) -> false + end, + Sum = fun({_Tag, X}, Acc) -> Acc+X end, + + %% util() + ?line Util1 = cpu_sup:util(), + ?line true = is_number(Util1), + ?line true = Util1>0, + ?line Util2 = cpu_sup:util(), + ?line true = is_number(Util2), + ?line true = Util2>0, + + %% util([]) + ?line {all, Busy1, NonBusy1, []} = cpu_sup:util([]), + ?line 100.00 = Busy1 + NonBusy1, + + %% util([detailed]) + ?line {Cpus2, Busy2, NonBusy2, []} = cpu_sup:util([detailed]), + ?line true = lists:all(fun(X) -> is_integer(X) end, Cpus2), + ?line true = lists:all(BusyP, Busy2), + ?line true = lists:all(NonBusyP, NonBusy2), + ?line 100.00 = lists:foldl(Sum,0,Busy2)+lists:foldl(Sum,0,NonBusy2), + + %% util([per_cpu]) + ?line [{Cpu3, Busy3, NonBusy3, []}|_] = cpu_sup:util([per_cpu]), + ?line true = is_integer(Cpu3), + ?line 100.00 = Busy3 + NonBusy3, + + %% util([detailed, per_cpu]) + ?line [{Cpu4, Busy4, NonBusy4, []}|_] = + cpu_sup:util([detailed, per_cpu]), + ?line true = is_integer(Cpu4), + ?line true = lists:all(BusyP, Busy2), + ?line true = lists:all(NonBusyP, NonBusy2), + ?line 100.00 = lists:foldl(Sum,0,Busy4)+lists:foldl(Sum,0,NonBusy4), + + %% bad util/1 calls + ?line {'EXIT',{badarg,_}} = (catch cpu_sup:util(detailed)), + ?line {'EXIT',{badarg,_}} = (catch cpu_sup:util([detialed])), + + ok. + +-define(SPIN_TIME, 1000). + +util_values(suite) -> + []; +util_values(doc) -> + ["Test utilization values"]; +util_values(Config) when is_list(Config) -> + + Tester = self(), + Ref = make_ref(), + Loop = fun (L) -> L(L) end, + Spinner = fun () -> + Looper = spawn_link(fun () -> Loop(Loop) end), + receive after ?SPIN_TIME -> ok end, + unlink(Looper), + exit(Looper, kill), + Tester ! Ref + end, + + ?line cpu_sup:util(), + + ?line spawn_link(Spinner), + ?line receive Ref -> ok end, + ?line HighUtil1 = cpu_sup:util(), + + ?line receive after ?SPIN_TIME -> ok end, + ?line LowUtil1 = cpu_sup:util(), + + ?line spawn_link(Spinner), + ?line receive Ref -> ok end, + ?line HighUtil2 = cpu_sup:util(), + + ?line receive after ?SPIN_TIME -> ok end, + ?line LowUtil2 = cpu_sup:util(), + + Utils = [{high1,HighUtil1}, {low1,LowUtil1}, + {high2,HighUtil2}, {low2,LowUtil2}], + ?t:format("Utils: ~p~n", [Utils]), + + ?line false = LowUtil1 > HighUtil1, + ?line false = LowUtil1 > HighUtil2, + ?line false = LowUtil2 > HighUtil1, + ?line false = LowUtil2 > HighUtil2, + + ok. + + +% Outdated +% The portprogram is now restarted if killed, and not by os_mon... + +port(suite) -> + []; +port(doc) -> + ["Test that cpu_sup handles a terminating port program"]; +port(Config) when is_list(Config) -> + case cpu_sup_os_pid() of + {ok, PidStr} -> + %% Monitor cpu_sup + ?line MonRef = erlang:monitor(process, cpu_sup), + ?line N1 = cpu_sup:nprocs(), + ?line true = N1>0, + + %% Kill the port program + case os:cmd("kill -9 " ++ PidStr) of + [] -> + %% cpu_sup should not terminate + receive + {'DOWN', MonRef, _, _, Reason} -> + ?line ?t:fail({unexpected_exit_reason, Reason}) + after 3000 -> + ok + end, + + %% Give cpu_sup time to restart cpu_sup port + ?t:sleep(?t:seconds(3)), + ?line N2 = cpu_sup:nprocs(), + ?line true = N2>0, + + erlang:demonitor(MonRef), + ok; + + Line -> + erlang:demonitor(MonRef), + {skip, {not_killed, Line}} + end; + _ -> + {skip, os_pid_not_found } + end. + +terminate(suite) -> + []; +terminate(Config) when is_list(Config) -> + ?line ok = application:set_env(os_mon, start_cpu_sup, false), + ?line ok = supervisor:terminate_child(os_mon_sup, cpu_sup), + ok. + +unavailable(suite) -> + []; +unavailable(doc) -> + ["Test correct behaviour when service is unavailable"]; +unavailable(Config) when is_list(Config) -> + + %% Make sure all API functions return their dummy values + ?line 0 = cpu_sup:nprocs(), + ?line 0 = cpu_sup:avg1(), + ?line 0 = cpu_sup:avg5(), + ?line 0 = cpu_sup:avg15(), + ?line 0 = cpu_sup:util(), + ?line {all,0,0,[]} = cpu_sup:util([]), + ?line {all,0,0,[]} = cpu_sup:util([detailed]), + ?line {all,0,0,[]} = cpu_sup:util([per_cpu]), + ?line {all,0,0,[]} = cpu_sup:util([detailed,per_cpu]), + + ok. + +restart(suite) -> + []; +restart(Config) when is_list(Config) -> + ?line ok = application:set_env(os_mon, start_cpu_sup, true), + ?line {ok, _Pid} = supervisor:restart_child(os_mon_sup, cpu_sup), + ok. + +%% Aux + +cpu_sup_os_pid() -> + Str = os:cmd("ps -e | grep '[c]pu_sup'"), + case io_lib:fread("~s", Str) of + {ok, [Pid], _Rest} -> {ok, Pid}; + _ -> {error, pid_not_found} + end. diff --git a/lib/os_mon/test/disksup_SUITE.erl b/lib/os_mon/test/disksup_SUITE.erl new file mode 100644 index 0000000000..987d631c36 --- /dev/null +++ b/lib/os_mon/test/disksup_SUITE.erl @@ -0,0 +1,426 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(disksup_SUITE). +-include("test_server.hrl"). + +%% Test server specific exports +-export([all/1]). +-export([init_per_suite/1, end_per_suite/1]). +-export([init_per_testcase/2, end_per_testcase/2]). + +%% Test cases +-export([api/1, config/1, alarm/1]). +-export([port/1]). +-export([terminate/1, unavailable/1, restart/1]). +-export([otp_5910/1]). + +%% Default timetrap timeout (set in init_per_testcase) +-define(default_timeout, ?t:minutes(1)). + +init_per_suite(Config) when is_list(Config) -> + ?line ok = application:start(os_mon), + Config. + +end_per_suite(Config) when is_list(Config) -> + ?line ok = application:stop(os_mon), + Config. + +init_per_testcase(_Case, Config) -> + Dog = ?t:timetrap(?default_timeout), + [{watchdog,Dog} | Config]. + +end_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +all(suite) -> + Bugs = [otp_5910], + case ?t:os_type() of + {unix, sunos} -> + [api, config, alarm, port, + {conf, terminate, [unavailable], restart}] ++ Bugs; + {unix, _OSname} -> + [api, alarm] ++ Bugs; + {win32, _OSname} -> + [api, alarm] ++ Bugs; + _OS -> + [unavailable] + end. + +api(suite) -> + []; +api(doc) -> + ["Test of API functions"]; +api(Config) when is_list(Config) -> + + %% get_disk_data() + ?line [{Id, KByte, Capacity}|_] = disksup:get_disk_data(), + ?line true = io_lib:printable_list(Id), + ?line true = is_integer(KByte), + ?line true = is_integer(Capacity), + ?line true = KByte>0, + ?line true = Capacity>0, + + %% get_check_interval() + ?line 1800000 = disksup:get_check_interval(), + + %% set_check_interval(Minutes) + ?line ok = disksup:set_check_interval(20), + ?line 1200000 = disksup:get_check_interval(), + ?line {'EXIT',{badarg,_}} = (catch disksup:set_check_interval(0.5)), + ?line 1200000 = disksup:get_check_interval(), + ?line ok = disksup:set_check_interval(30), + + %% get_almost_full_threshold() + ?line 80 = disksup:get_almost_full_threshold(), + + %% set_almost_full_threshold(Float) + ?line ok = disksup:set_almost_full_threshold(0.90), + ?line 90 = disksup:get_almost_full_threshold(), + ?line {'EXIT',{badarg,_}} = + (catch disksup:set_almost_full_threshold(-0.5)), + ?line 90 = disksup:get_almost_full_threshold(), + ?line ok = disksup:set_almost_full_threshold(0.80), + + ok. + +config(suite) -> + []; +config(doc) -> + ["Test configuration"]; +config(Config) when is_list(Config) -> + + %% Change configuration parameters and make sure change is reflected + %% when disksup is restarted + ?line ok = + application:set_env(os_mon, disk_space_check_interval, 29), + ?line ok = + application:set_env(os_mon, disk_almost_full_threshold, 0.81), + + ?line ok = supervisor:terminate_child(os_mon_sup, disksup), + ?line {ok, _Child1} = supervisor:restart_child(os_mon_sup, disksup), + + ?line 1740000 = disksup:get_check_interval(), + ?line 81 = disksup:get_almost_full_threshold(), + + %% Also try this with bad parameter values, should be ignored + ?line ok = + application:set_env(os_mon, disk_space_check_interval, 0.5), + ?line ok = + application:set_env(os_mon, disk_almost_full_threshold, -0.81), + + ?line ok = supervisor:terminate_child(os_mon_sup, disksup), + ?line {ok, _Child2} = supervisor:restart_child(os_mon_sup, disksup), + + ?line 1800000 = disksup:get_check_interval(), + ?line 80 = disksup:get_almost_full_threshold(), + + %% Reset configuration parameters + ?line ok = + application:set_env(os_mon, disk_space_check_interval, 30), + ?line ok = + application:set_env(os_mon, disk_almost_full_threshold, 0.80), + + ok. + +%%---------------------------------------------------------------------- +%% NOTE: The test case is a bit weak as it will fail if the disk usage +%% changes too much during its course, or if there are timing problems +%% with the alarm_handler receiving the alarms too late +%%---------------------------------------------------------------------- +alarm(suite) -> + []; +alarm(doc) -> + ["Test that alarms are set and cleared"]; +alarm(Config) when is_list(Config) -> + + %% Find out how many disks exceed the threshold + %% and make sure the corresponding number of alarms is set + ?line Threshold1 = disksup:get_almost_full_threshold(), % 80 + ?line Data1 = disksup:get_disk_data(), + ?line Over1 = over_threshold(Data1, Threshold1), + ?line Alarms1 = get_alarms(), + if + Over1==length(Alarms1) -> + ?line true; + true -> + dump_info(), + ?line ?t:fail({bad_alarms, Threshold1, Data1, Alarms1}) + end, + + %% Try to find a disk with space usage below Threshold1, + %% lower the threshold accordingly and make sure new alarms are set + Fun1 = fun({_Id, _Kbyte, Capacity}) -> + if + Capacity>0, Capacity<Threshold1 -> true; + true -> false + end + end, + ?line case until(Fun1, Data1) of + {_, _, Cap1} -> + Threshold2 = Cap1-1, + ?line ok = + disksup:set_almost_full_threshold(Threshold2/100), + ?line disksup ! timeout, % force a disk check + ?line Data2 = disksup:get_disk_data(), + ?line Over2 = over_threshold(Data2, Threshold2), + ?line Alarms2 = get_alarms(), + if + Over2==length(Alarms2), Over2>Over1 -> + ?line true; + true -> + dump_info(), + ?line ?t:fail({bad_alarms, Threshold2, Data2, Alarms2}) + end; + false -> + ?line ignore + end, + + %% Find out the highest space usage among all disks + %% and try to raise the threshold above this value, + %% make sure all alarms are cleared + Fun2 = fun({_Id, _Kbyte, Capacity}, MaxAcc) -> + if + Capacity>MaxAcc -> Capacity; + true -> MaxAcc + end + end, + ?line case lists:foldl(Fun2, 0, Data1) of + Max when Max<100 -> + Threshold3 = Max+1, + ?line ok = + disksup:set_almost_full_threshold(Threshold3/100), + ?line disksup ! timeout, % force a disk check + ?line Data3 = disksup:get_disk_data(), + ?line Over3 = over_threshold(Data3, Threshold3), + ?line Alarms3 = get_alarms(), + if + Over3==0, length(Alarms3)==0 -> + ?line ok; + true -> + dump_info(), + ?line ?t:fail({bad_alarms, Threshold3, Data3, Alarms3}) + end; + 100 -> + ?line ignore + end, + + %% Reset threshold + ?line ok = disksup:set_almost_full_threshold(Threshold1/100), + + ok. + +over_threshold(Data, Threshold) -> + Data2 = remove_duplicated_disks(lists:keysort(1, Data)), + lists:foldl(fun({_Id, _Kbyte, Cap}, N) when Cap>=Threshold -> + N+1; + (_DiskData, N) -> + N + end, + 0, + Data2). + +%% On some platforms (for example MontaVista) data for one disk can be +%% "duplicated": +%% Linux ppb 2.4.20_mvl31-pcore680 #1 Sun Feb 1 23:12:56 PST 2004 ppc unknown +%% +%% MontaVista(R) Linux(R) Professional Edition 3.1 +%% +%% [ppb:~]> /bin/df -lk +%% Filesystem 1k-blocks Used Available Use% Mounted on +%% rootfs 8066141 3023763 4961717 38% / +%% /dev/root 8066141 3023763 4961717 38% / +%% tmpfs 192892 0 192892 0% /dev/shm +%% +%% disksup: +%% [{"/",8066141,38}, {"/",8066141,38}, {"/dev/shm",192892,0}] +%% +%% disksup will only set ONE alarm for "/". +%% Therefore the list of disk data must be sorted and duplicated disk +%% tuples removed before calculating how many alarms should be set, or +%% the testcase will fail erroneously. +remove_duplicated_disks([{Id, _, _}, {Id, Kbyte, Cap}|T]) -> + remove_duplicated_disks([{Id, Kbyte, Cap}|T]); +remove_duplicated_disks([H|T]) -> + [H|remove_duplicated_disks(T)]; +remove_duplicated_disks([]) -> + []. + +get_alarms() -> + lists:filter(fun({{disk_almost_full, _Disk},_}) -> true; + (_) -> false + end, + alarm_handler:get_alarms()). + +until(Fun, [H|T]) -> + case Fun(H) of + true -> H; + false -> + until(Fun, T) + end; +until(_Fun, []) -> + false. + +port(suite) -> + []; +port(doc) -> + ["Test that disksup handles a terminating port program"]; +port(Config) when is_list(Config) -> + ?line Str = os:cmd("ps -ef | grep '[d]isksup'"), + case io_lib:fread("~s ~s", Str) of + {ok, [_Uid,Pid], _Rest} -> + + %% Monitor disksup + ?line MonRef = erlang:monitor(process, disksup), + ?line [{_Disk1,Kbyte1,_Cap1}|_] = disksup:get_disk_data(), + ?line true = Kbyte1>0, + + %% Kill the port program + case os:cmd("kill -9 " ++ Pid) of + [] -> + + %% disksup should now terminate + receive + {'DOWN', MonRef, _, _, {port_died, _Reason}} -> + ok; + {'DOWN', MonRef, _, _, Reason} -> + ?line ?t:fail({unexpected_exit_reason, Reason}) + after + 3000 -> + ?line ?t:fail({still_alive, Str}) + end, + + %% Give os_mon_sup time to restart disksup + ?t:sleep(?t:seconds(3)), + ?line [{_Disk2,Kbyte2,_Cap2}|_] = + disksup:get_disk_data(), + ?line true = Kbyte2>0, + + ok; + + Line -> + erlang:demonitor(MonRef), + {skip, {not_killed, Line}} + end; + _ -> + {skip, {os_pid_not_found, Str}} + end. + +terminate(suite) -> + []; +terminate(Config) when is_list(Config) -> + ?line ok = application:set_env(os_mon, start_disksup, false), + ?line ok = supervisor:terminate_child(os_mon_sup, disksup), + ok. + +unavailable(suite) -> + []; +unavailable(doc) -> + ["Test correct behaviour when service is unavailable"]; +unavailable(Config) when is_list(Config) -> + + %% Make sure all API functions return their dummy values + ?line [{"none",0,0}] = disksup:get_disk_data(), + ?line 1800000 = disksup:get_check_interval(), + ?line ok = disksup:set_check_interval(5), + ?line 80 = disksup:get_almost_full_threshold(), + ?line ok = disksup:set_almost_full_threshold(0.9), + + ok. + +restart(suite) -> + []; +restart(Config) when is_list(Config) -> + ?line ok = application:set_env(os_mon, start_disksup, true), + ?line {ok, _Pid} = supervisor:restart_child(os_mon_sup, disksup), + ok. + +otp_5910(suite) -> + []; +otp_5910(doc) -> + ["Test that alarms are cleared if disksup crashes or " + "if OS_Mon is stopped"]; +otp_5910(Config) when is_list(Config) -> + + %% Make sure disksup sets at least one alarm + ?line Data = disksup:get_disk_data(), + ?line Threshold0 = disksup:get_almost_full_threshold(), + ?line Threshold = case over_threshold(Data, Threshold0) of + 0 -> + [{_Id,_Kbyte,Cap}|_] = Data, + ?line ok = disksup:set_almost_full_threshold((Cap-1)/100), + Cap-1; + _N -> + Threshold0 + end, + ?line ok = application:set_env(os_mon, + disk_almost_full_threshold, + Threshold/100), + ?line disksup ! timeout, % force a disk check + ?line Data2 = disksup:get_disk_data(), + ?line Over = over_threshold(Data2, Threshold), + ?line Alarms = get_alarms(), + if + Over==0 -> + ?line ?t:fail({threshold_too_low, Data2, Threshold}); + Over==length(Alarms) -> + ok; + true -> + dump_info(), + ?line ?t:fail({bad_alarms, Threshold, Data2, Alarms}) + end, + + %% Kill disksup + exit(whereis(disksup), faked_disksup_crash), + + %% Wait a little to make sure disksup has been restarted, + %% then make sure the alarms are set once, but not twice + ?t:sleep(?t:seconds(1)), + ?line Data3 = disksup:get_disk_data(), + ?line Alarms2 = get_alarms(), + if + length(Alarms2)==length(Alarms) -> + ok; + true -> + dump_info(), + ?line ?t:fail({bad_alarms, Threshold, Data3, Alarms,Alarms2}) + end, + + %% Stop OS_Mon and make sure all disksup alarms are cleared + ?line ok = application:stop(os_mon), + ?t:sleep(?t:seconds(1)), + ?line Alarms3 = get_alarms(), + if + length(Alarms3)==0 -> + ok; + true -> + ?line ?t:fail({alarms_not_cleared, Alarms3}) + end, + + %% Reset threshold and restart OS_Mon + ?line ok = application:set_env(os_mon, + disksup_almost_full_threshold, 0.8), + ?line ok = disksup:set_almost_full_threshold(0.8), + ?line ok = application:start(os_mon), + + ok. + +dump_info() -> + io:format("Status: ~p~n", [sys:get_status(disksup)]). diff --git a/lib/os_mon/test/memsup_SUITE.erl b/lib/os_mon/test/memsup_SUITE.erl new file mode 100644 index 0000000000..01a7f6c7f2 --- /dev/null +++ b/lib/os_mon/test/memsup_SUITE.erl @@ -0,0 +1,782 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(memsup_SUITE). +-include("test_server.hrl"). + +%% Test server specific exports +-export([all/1]). +-export([init_per_suite/1, end_per_suite/1]). +-export([init_per_testcase/2, end_per_testcase/2]). + +%% Test cases +-export([api/1, alarm1/1, alarm2/1, process/1]). +-export([config/1, timeout/1, unavailable/1, port/1]). +-export([otp_5910/1]). + +%% Default timetrap timeout (set in init_per_testcase) +-define(default_timeout, ?t:minutes(1)). + +init_per_suite(Config) when is_list(Config) -> + ?line ok = application:start(os_mon), + Config. + +end_per_suite(Config) when is_list(Config) -> + ?line ok = application:stop(os_mon), + Config. + +init_per_testcase(_Case, Config) -> + Dog = ?t:timetrap(?default_timeout), + [{watchdog,Dog} | Config]. + +end_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + Config. + +all(suite) -> + All = case ?t:os_type() of + {unix, sunos} -> + [api, alarm1, alarm2, process, + config, timeout, unavailable, port]; + {unix, linux} -> + [api, alarm1, alarm2, process, timeout]; + _OS -> + [api, alarm1, alarm2, process] + end, + Bugs = [otp_5910], + All ++ Bugs. + +api(suite) -> + []; +api(doc) -> + ["Test of API functions"]; +api(Config) when is_list(Config) -> + + %% get_memory_data() + ?line RegMemData = memsup:get_memory_data(), + case RegMemData of + {TotMem, AllBytes, {Pid, PidBytes}} when is_integer(TotMem), + is_integer(AllBytes), + is_pid(Pid), + is_integer(PidBytes) -> + ok; + {0, 0, _WorstPid} -> + ?line ?t:fail(first_data_collection_failed); + _ -> + ?line ?t:fail({bad_return, RegMemData}) + end, + + %% get_system_memory_data() + ?line ExtMemData = memsup:get_system_memory_data(), + Tags = [ total_memory, + free_memory, + system_total_memory, + largest_free, + number_of_free, + free_swap, + total_swap, + cached_memory, + buffered_memory, + shared_memory], + + ?line true = lists:all(fun({Tag,Value}) when is_atom(Tag), + is_integer(Value) -> + lists:member(Tag, Tags); + (_) -> + false + end, + ExtMemData), + + %% get_os_wordsize() + ?line ok = case memsup:get_os_wordsize() of + 32 -> ok; + 64 -> ok; + unsupported_os -> ok; + _ -> error + end, + + %% get_check_interval() + ?line 60000 = memsup:get_check_interval(), + + %% set_check_interval(Minutes) + ?line ok = memsup:set_check_interval(2), + ?line 120000 = memsup:get_check_interval(), + ?line {'EXIT',{badarg,_}} = + (catch memsup:set_check_interval(0.2)), + ?line 120000 = memsup:get_check_interval(), + ?line ok = memsup:set_check_interval(1), + + %% get_procmem_high_watermark() + ?line 5 = memsup:get_procmem_high_watermark(), + + %% set_procmem_high_watermark() + ?line ok = memsup:set_procmem_high_watermark(0.1), + ?line 10 = memsup:get_procmem_high_watermark(), + ?line {'EXIT',{badarg,_}} = + (catch memsup:set_procmem_high_watermark(-0.1)), + ?line 10 = memsup:get_procmem_high_watermark(), + ?line ok = memsup:set_procmem_high_watermark(0.05), + + %% get_sysmem_high_watermark() + ?line 80 = memsup:get_sysmem_high_watermark(), + + %% set_sysmem_high_watermark() + ?line ok = memsup:set_sysmem_high_watermark(0.9), + ?line 90 = memsup:get_sysmem_high_watermark(), + ?line {'EXIT',{badarg,_}} = + (catch memsup:set_sysmem_high_watermark(-0.9)), + ?line 90 = memsup:get_sysmem_high_watermark(), + ?line ok = memsup:set_sysmem_high_watermark(0.8), + + %% get|set_helper_timeout + ?line 30 = memsup:get_helper_timeout(), + ?line ok = memsup:set_helper_timeout(29), + ?line 29 = memsup:get_helper_timeout(), + ?line {'EXIT',{badarg,_}} = (catch memsup:set_helper_timeout(31.0)), + ?line 29 = memsup:get_helper_timeout(), + ok. + +%%---------------------------------------------------------------------- +%% NOTE: The test case is a bit weak as it will fail if the memory +%% usage changes too much during its course. +%%---------------------------------------------------------------------- +alarm1(suite) -> + []; +alarm1(doc) -> + ["Test alarms when memsup_system_only==false"]; +alarm1(Config) when is_list(Config) -> + + %% If system memory usage is too high, the testcase cannot + %% be run correctly + ?line {Total, Alloc, {_Pid,_PidAlloc}} = memsup:get_memory_data(), + io:format("alarm1: Total: ~p, Alloc: ~p~n", [Total, Alloc]), + ?line SysUsage = Alloc/Total, + if + SysUsage>0.99 -> + {skip, sys_mem_too_high}; + true -> + alarm1(Config, SysUsage) + end. + +alarm1(_Config, SysUsage) -> + %% Set a long memory check interval, we will force memory checks + %% instead + ?line ok = memsup:set_check_interval(60), + + %% Check thresholds + ?line SysThreshold = (memsup:get_sysmem_high_watermark()/100), + ?line ProcThreshold = (memsup:get_procmem_high_watermark()/100), + + %% Check if a system alarm already should be set or not + SysP = if + SysUsage>SysThreshold -> true; + SysUsage=<SysThreshold -> false + end, + + %% If system memory is higher than threshold, make sure the system + %% alarm is set. Otherwise, make sure it is not set + case alarm_set(system_memory_high_watermark) of + {true, []} when SysP -> + ok; + false when not SysP -> + ok; + _ -> + ?line ?t:fail({sys_alarm, SysUsage, SysThreshold}) + end, + + %% Lower/raise the threshold to clear/set the alarm + NewSysThreshold = if + SysP -> + Value = 1.1*SysUsage, + if + Value > 0.99 -> 0.99; + true -> Value + end; + not SysP -> 0.9*SysUsage + end, + + ?line ok = memsup:set_sysmem_high_watermark(NewSysThreshold), + + %% Initiate and wait for a new data collection + ?line ok = force_collection(), + + %% Make sure the alarm is cleared/set + ?t:sleep(?t:seconds(5)), + case alarm_set(system_memory_high_watermark) of + {true, []} when not SysP -> + ok; + false when SysP -> + ok; + _ -> + ?line ?t:fail({sys_alarm, SysUsage, NewSysThreshold}) + end, + + %% Reset the threshold to set/clear the alarm again + ?line ok = memsup:set_sysmem_high_watermark(SysThreshold), + ?line ok = force_collection(), + ?t:sleep(?t:seconds(1)), + case alarm_set(system_memory_high_watermark) of + {true, []} when SysP -> + ok; + false when not SysP -> + ok; + _ -> + ?line ?t:fail({sys_alarm, SysUsage, SysThreshold}) + end, + + %% Check memory usage + ?line {Total2, _, {WorstPid, PidAlloc}} = memsup:get_memory_data(), + + %% Check if a process alarm already should be set or not + PidUsage = PidAlloc/Total2, + ProcP = if + PidUsage>ProcThreshold -> true; + PidUsage=<ProcThreshold -> false + end, + + %% Make sure the process alarm is set/not set accordingly + case alarm_set(process_memory_high_watermark) of + {true, WorstPid} when ProcP -> + ok; + false when not ProcP -> + ok; + {true, BadPid1} when ProcP -> + ?line ?t:fail({proc_alarm, WorstPid, BadPid1}); + _ -> + ?line ?t:fail({proc_alarm, PidUsage, ProcThreshold}) + end, + + %% Lower/raise the threshold to clear/set the alarm + NewProcThreshold = if + ProcP -> 1.1*PidUsage; + not ProcP -> 0.9*PidUsage + end, + ?line ok = memsup:set_procmem_high_watermark(NewProcThreshold), + ?line ok = force_collection(), + ?t:sleep(?t:seconds(1)), + case alarm_set(process_memory_high_watermark) of + {true, WorstPid} when not ProcP -> + ok; + false when ProcP -> + ok; + {true, BadPid2} when not ProcP -> + ?line test_server:fail({proc_alarm, WorstPid, BadPid2}); + _ -> + ?line ?t:fail({proc_alarm, PidUsage, ProcThreshold}) + end, + + %% Reset the threshold to clear/set the alarm + ?line ok = memsup:set_procmem_high_watermark(ProcThreshold), + ?line ok = force_collection(), + ?t:sleep(?t:seconds(1)), + case alarm_set(process_memory_high_watermark) of + {true, WorstPid} when ProcP -> + ok; + false when not ProcP -> + ok; + {true, BadPid3} when ProcP -> + ?line test_server:fail({proc_alarm, WorstPid, BadPid3}); + _ -> + ?line ?t:fail({proc_alarm, PidUsage, ProcThreshold}) + end, + + %% Reset memory check interval + ?line ok = memsup:set_check_interval(1), + ok. + +alarm2(suite) -> + []; +alarm2(doc) -> + ["Test alarms when memsup_system_only==true"]; +alarm2(Config) when is_list(Config) -> + + %% If system memory usage is too high, the testcase cannot + %% be run correctly + ?line {Total, Alloc, {_Pid,_PidAlloc}} = memsup:get_memory_data(), + ?line SysUsage = Alloc/Total, + if + SysUsage>0.99 -> + {skip, sys_mem_too_high}; + true -> + alarm2(Config, SysUsage) + end. + +alarm2(_Config, _SysUsage) -> + + %% Change memsup_system_only and restart memsup + ?line ok = application:set_env(os_mon, memsup_system_only, true), + ?line ok = supervisor:terminate_child(os_mon_sup, memsup), + ?line {ok, _Memsup1} = supervisor:restart_child(os_mon_sup, memsup), + + %% Set a long memory check interval, we will force memory checks + %% instead + ?line ok = memsup:set_check_interval(60), + + %% Check data and thresholds + ?line {Total, Alloc, undefined} = memsup:get_memory_data(), + ?line SysThreshold = (memsup:get_sysmem_high_watermark()/100), + ?line true = is_integer(memsup:get_procmem_high_watermark()), + + %% Check if a system alarm already should be set or not + ?line SysUsage = Alloc/Total, + SysP = if + SysUsage>SysThreshold -> true; + SysUsage=<SysThreshold -> false + end, + + %% If system memory is higher than threshold, make sure the system + %% alarm is set. Otherwise, make sure it is not set + case alarm_set(system_memory_high_watermark) of + {true, []} when SysP -> + ok; + false when not SysP -> + ok; + _ -> + ?line ?t:fail({sys_alarm, SysUsage, SysThreshold}) + end, + + %% Lower/raise the threshold to clear/set the alarm + NewSysThreshold = if + SysP -> + Value = 1.1*SysUsage, + if + Value > 0.99 -> 0.99; + true -> Value + end; + not SysP -> 0.9*SysUsage + end, + + ?line ok = memsup:set_sysmem_high_watermark(NewSysThreshold), + + %% Initiate and wait for a new data collection + ?line ok = force_collection(), + + %% Make sure the alarm is cleared/set + ?t:sleep(?t:seconds(1)), + case alarm_set(system_memory_high_watermark) of + {true, []} when not SysP -> + ok; + false when SysP -> + ok; + _ -> + ?line ?t:fail({sys_alarm, SysUsage, NewSysThreshold}) + end, + + %% Reset the threshold to set/clear the alarm again + ?line ok = memsup:set_sysmem_high_watermark(SysThreshold), + ?line ok = force_collection(), + ?t:sleep(?t:seconds(1)), + case alarm_set(system_memory_high_watermark) of + {true, []} when SysP -> + ok; + false when not SysP -> + ok; + _ -> + ?line ?t:fail({sys_alarm, SysUsage, SysThreshold}) + end, + + %% Reset memsup_system_only and restart memsup + %% (memory check interval is then automatically reset) + ?line ok = application:set_env(os_mon, memsup_system_only, false), + ?line ok = supervisor:terminate_child(os_mon_sup, memsup), + ?line {ok, _Memsup2} = supervisor:restart_child(os_mon_sup, memsup), + + ok. + +alarm_set(Alarm) -> + alarm_set(Alarm, alarm_handler:get_alarms()). +alarm_set(Alarm, [{Alarm,Data}|_]) -> + {true,Data}; +alarm_set(Alarm, [_|T]) -> + alarm_set(Alarm, T); +alarm_set(_Alarm, []) -> + false. + +process(suite) -> + []; +process(doc) -> + ["Make sure memsup discovers a process grown very large"]; +process(Config) when is_list(Config) -> + + %% Set a long memory check interval, we will force memory checks + %% instead + ?line ok = memsup:set_check_interval(60), + + %% Collect data + MemData = memsup:get_memory_data(), + io:format("process: memsup:get_memory_data() = ~p~n", [MemData]), + ?line {_Total,_Free,{_,Bytes}} = MemData, + + %% Start a new process larger than Worst + ?line WorsePid = spawn(fun() -> new_hog(Bytes) end), + ?t:sleep(?t:seconds(1)), + + %% Initiate and wait for a new data collection + ?line ok = force_collection(), + + %% Check that get_memory_data() returns updated result + ?line case memsup:get_memory_data() of + {_, _, {WorsePid, _MoreBytes}} -> + ok; + {_, _, BadWorst} -> + ?line ?t:fail({worst_pid, BadWorst}) + end, + + %% Reset memory check interval + ?line exit(WorsePid, done), + ?line ok = memsup:set_check_interval(1), + ok. + +new_hog(Bytes) -> + WordSize = erlang:system_info(wordsize), + N = (Bytes+200) div WordSize div 2, + List = lists:duplicate(N, a), + new_hog_1(List). + +new_hog_1(List) -> + receive + _Any -> exit(List) + end. + +config(suite) -> + []; +config(doc) -> + ["Test configuration"]; +config(Config) when is_list(Config) -> + + %% Change configuration parameters and make sure change is reflected + %% when memsup is restarted + ?line ok = application:set_env(os_mon, memory_check_interval, 2), + ?line ok = + application:set_env(os_mon, system_memory_high_watermark, 0.9), + ?line ok = + application:set_env(os_mon, process_memory_high_watermark, 0.1), + ?line ok = application:set_env(os_mon, memsup_helper_timeout, 35), + ?line ok = application:set_env(os_mon, memsup_system_only, true), + + ?line ok = supervisor:terminate_child(os_mon_sup, memsup), + ?line {ok, _Child1} = supervisor:restart_child(os_mon_sup, memsup), + + ?line 120000 = memsup:get_check_interval(), + ?line 90 = memsup:get_sysmem_high_watermark(), + ?line 10 = memsup:get_procmem_high_watermark(), + ?line 35 = memsup:get_helper_timeout(), + + %% Also try this with bad parameter values, should be ignored + ?line ok = application:set_env(os_mon, memory_check_interval, 0.2), + ?line ok = + application:set_env(os_mon, system_memory_high_watermark, -0.9), + ?line ok = + application:set_env(os_mon, process_memory_high_watermark,-0.1), + ?line ok = application:set_env(os_mon, memsup_helper_timeout, 0.35), + ?line ok = application:set_env(os_mon, memsup_system_only, arne), + + ?line ok = supervisor:terminate_child(os_mon_sup, memsup), + ?line {ok, _Child2} = supervisor:restart_child(os_mon_sup, memsup), + + ?line 60000 = memsup:get_check_interval(), + ?line 80 = memsup:get_sysmem_high_watermark(), + ?line 5 = memsup:get_procmem_high_watermark(), + ?line 30 = memsup:get_helper_timeout(), + + %% Reset configuration parameters + ?line ok = application:set_env(os_mon, memory_check_interval, 1), + ?line ok = + application:set_env(os_mon, system_memory_high_watermark, 0.8), + ?line ok = + application:set_env(os_mon, process_memory_high_watermark,0.05), + ?line ok = application:set_env(os_mon, memsup_helper_timeout, 30), + ?line ok = application:set_env(os_mon, memsup_system_only, false), + + ok. + +unavailable(suite) -> + []; +unavailable(doc) -> + ["Test correct behaviour when service is unavailable"]; +unavailable(Config) when is_list(Config) -> + + %% Close memsup + ?line ok = application:set_env(os_mon, start_memsup, false), + ?line ok = supervisor:terminate_child(os_mon_sup, memsup), + + %% Make sure all API functions return their dummy values + ?line {0,0,{_Pid,0}} = memsup:get_memory_data(), + ?line ok = application:set_env(os_mon, memsup_system_only, true), + ?line {0,0,undefined} = memsup:get_memory_data(), + ?line ok = application:set_env(os_mon, memsup_system_only, false), + ?line [] = memsup:get_system_memory_data(), + ?line 0 = memsup:get_os_wordsize(), + ?line 60000 = memsup:get_check_interval(), + ?line ok = memsup:set_check_interval(2), + ?line 5 = memsup:get_procmem_high_watermark(), + ?line ok = memsup:set_procmem_high_watermark(0.10), + ?line 80 = memsup:get_sysmem_high_watermark(), + ?line ok = memsup:set_sysmem_high_watermark(0.90), + ?line 30 = memsup:get_helper_timeout(), + ?line ok = memsup:set_helper_timeout(35), + + %% Start memsup again, + ?line ok = application:set_env(os_mon, start_memsup, true), + ?line {ok, _Child} = supervisor:restart_child(os_mon_sup, memsup), + + ok. + +timeout(suite) -> + []; +timeout(doc) -> + ["Test stability of memsup when data collection times out"]; +timeout(Config) when is_list(Config) -> + + %% Set a long memory check interval and memsup_helper timeout, + %% we will force memory checks instead and fake timeouts + ?line ok = memsup:set_check_interval(60), + ?line ok = memsup:set_helper_timeout(3600), + + %% Provoke a timeout during memory collection + ?line memsup ! time_to_collect, + ?line memsup ! reg_collection_timeout, + + %% Not much we can check though, except that memsup is still running + ?line {_,_,_} = memsup:get_memory_data(), + + %% Provoke a timeout during extensive memory collection + %% We fake a gen_server:call/2 to be able to send a timeout message + %% while the request is being handled + + %% Linux should be handled the same way as solaris. + +% TimeoutMsg = case ?t:os_type() of +% {unix, sunos} -> ext_collection_timeout; +% {unix, linux} -> reg_collection_timeout +% end, + + TimeoutMsg = ext_collection_timeout, + + ?line Pid = whereis(memsup), + ?line Mref = erlang:monitor(process, Pid), + ?line Pid ! {'$gen_call', {self(), Mref}, get_system_memory_data}, + ?line Pid ! TimeoutMsg, + receive + {Mref, []} -> + erlang:demonitor(Mref), + ?line ok; + {Mref, Res} -> + erlang:demonitor(Mref), + ?line ?t:fail({unexpected_result, Res}); + {'DOWN', Mref, _, _, _} -> + ?line ?t:fail(no_result) + end, + + %% Reset memory check interval and memsup_helper timeout + ?line ok = memsup:set_check_interval(1), + ?line ok = memsup:set_helper_timeout(30), + ?line memsup ! time_to_collect, + + ?line [_|_] = memsup:get_system_memory_data(), + + ok. + +port(suite) -> + []; +port(doc) -> + ["Test that memsup handles a terminating port program"]; +port(Config) when is_list(Config) -> + ?line Str = os:cmd("ps -e | grep '[m]emsup'"), + case io_lib:fread("~s", Str) of + {ok, [Pid], _Rest} -> + + %% Monitor memsup + ?line MonRef = erlang:monitor(process, memsup), + ?line {Total1,_Alloc1,_Worst1} = memsup:get_memory_data(), + ?line true = Total1>0, + + %% Kill the port program + case os:cmd("kill -9 " ++ Pid) of + [] -> + + %% memsup should now terminate + receive + {'DOWN', MonRef, _, _, {port_died, _Reason}} -> + ok; + {'DOWN', MonRef, _, _, Reason} -> + ?line ?t:fail({unexpected_exit_reason, Reason}) + after + 3000 -> + ?line ?t:fail(still_alive) + end, + + %% Give os_mon_sup time to restart memsup + ?t:sleep(?t:seconds(3)), + ?line {Total2,_Alloc2,_Worst2} = + memsup:get_memory_data(), + ?line true = Total2>0, + + ok; + + Line -> + erlang:demonitor(MonRef), + {skip, {not_killed, Line}} + end; + _ -> + {skip, {os_pid_not_found, Str}} + end. + +otp_5910(suite) -> + []; +otp_5910(doc) -> + ["Test that alarms are cleared and not set twice"]; +otp_5910(Config) when is_list(Config) -> + Alarms = + [system_memory_high_watermark, process_memory_high_watermark], + + %% Make sure memsup sets both alarms + ?line ok = application:set_env(os_mon, memory_check_interval, 60), + ?line ok = memsup:set_check_interval(60), + ?line SysThreshold = (memsup:get_sysmem_high_watermark()/100), + ?line ProcThreshold = (memsup:get_procmem_high_watermark()/100), + + MemData = memsup:get_memory_data(), + + io:format("otp_5910: memsup:get_memory_data() = ~p~n", [MemData]), + ?line {Total, Alloc, {_Pid, _Bytes}} = MemData, + ?line Pid = spawn_opt(fun() -> + receive + die -> ok + end + end, [{min_heap_size, 1000}]), + %% Create a process guaranteed to live, be constant and + %% break memsup process limit + ?line {memory, Bytes} = erlang:process_info(Pid,memory), + ?line SysUsage = Alloc/Total, + ?line ProcUsage = Bytes/Total, + + if + SysUsage>SysThreshold -> + ok; + SysUsage=<SysThreshold -> + ?line ok = application:set_env(os_mon, + sys_mem_high_watermark, + 0.5 * SysUsage), + ?line ok = memsup:set_sysmem_high_watermark(0.5 * SysUsage) + end, + if + ProcUsage>ProcThreshold -> + ok; + ProcUsage=<ProcThreshold -> + ?line ok = application:set_env(os_mon, + proc_mem_high_watermark, + 0.5 * ProcUsage), + ?line ok = memsup:set_procmem_high_watermark(0.5 *ProcUsage) + end, + ?line ok = force_collection(), + ?t:sleep(?t:seconds(1)), + lists:foreach(fun(AlarmId) -> + case alarm_set(AlarmId) of + {true, _} -> ok; + false -> + ?line ?t:fail({alarm_not_set, + AlarmId}) + end + end, + Alarms), + + %% Kill guaranteed process... + Pid ! die, + %% Kill memsup + exit(whereis(memsup), faked_memsup_crash), + %% Wait a little to make sure memsup has been restarted, + %% then make sure the alarms are set once, but not twice + ?t:sleep(?t:seconds(1)), + ?line MemUsage = memsup:get_memory_data(), + SetAlarms = alarm_handler:get_alarms(), + case lists:foldl(fun(system_memory_high_watermark, {S, P}) -> + {S+1, P}; + (process_memory_high_watermark, {S, P}) -> + {S, P+1}; + (_AlarmId, Acc0) -> + Acc0 + end, + {0, 0}, + SetAlarms) of + {0, 0} -> + ok; + _ -> + ?line ?t:fail({bad_number_of_alarms, SetAlarms, MemUsage}) + end, + + %% Stop OS_Mon and make sure all memsup alarms are cleared + ?line ok = application:stop(os_mon), + ?t:sleep(?t:seconds(1)), + lists:foreach(fun(AlarmId) -> + case alarm_set(AlarmId) of + false -> ok; + {true, _} -> + ?line ?t:fail({alarm_is_set, AlarmId}) + end + end, + Alarms), + + %% Reset configuration and restart OS_Mon + ?line ok = application:set_env(os_mon,memory_check_interval,1), + ?line ok = application:set_env(os_mon,sys_mem_high_watermark,0.8), + ?line ok = application:set_env(os_mon,proc_mem_high_watermark,0.05), + ?line ok = application:start(os_mon), + + ok. + +%%---------------------------------------------------------------------- +%% Auxiliary +%%---------------------------------------------------------------------- + +force_collection() -> + erlang:trace(whereis(memsup), true, ['receive']), + memsup ! time_to_collect, + TimerRef = erlang:send_after(5000, self(), timeout), + force_collection(TimerRef). + +force_collection(TimerRef) -> + receive + {trace, _Pid, 'receive', {collected_sys, _Sys}} -> + erlang:cancel_timer(TimerRef), + erlang:trace(whereis(memsup), false, ['receive']), + flush(), + ok; + {trace, _Pid, 'receive', reg_collection_timeout} -> + erlang:cancel_timer(TimerRef), + erlang:trace(whereis(memsup), false, ['receive']), + flush(), + collection_timeout; + timout -> + erlang:trace(whereis(memsup), false, ['receive']), + flush(), + timeout; + _Msg -> + force_collection(TimerRef) + end. + +flush() -> + receive + {trace, _, _, _} -> + flush(); + timeout -> + flush() + after 0 -> + ok + end. diff --git a/lib/os_mon/test/os_mon.spec b/lib/os_mon/test/os_mon.spec new file mode 100644 index 0000000000..bdae523795 --- /dev/null +++ b/lib/os_mon/test/os_mon.spec @@ -0,0 +1 @@ +{topcase, {dir, "../os_mon_test"}}. diff --git a/lib/os_mon/test/os_mon_SUITE.erl b/lib/os_mon/test/os_mon_SUITE.erl new file mode 100644 index 0000000000..ce52271ff8 --- /dev/null +++ b/lib/os_mon/test/os_mon_SUITE.erl @@ -0,0 +1,89 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(os_mon_SUITE). +-include("test_server.hrl"). + +%% Test server specific exports +-export([all/1]). +-export([init_per_testcase/2, fin_per_testcase/2]). + +%% Test cases +-export([app_file/1, config/1]). + +%% Default timetrap timeout (set in init_per_testcase) +-define(default_timeout, ?t:minutes(1)). + +init_per_testcase(_Case, Config) -> + Dog = test_server:timetrap(?default_timeout), + [{watchdog, Dog}|Config]. + +fin_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. + +all(suite) -> + case ?t:os_type() of + {unix, sunos} -> [app_file, config]; + _OS -> [app_file] + end. + +app_file(suite) -> + []; +app_file(doc) -> + ["Testing .app file"]; +app_file(Config) when is_list(Config) -> + ?line ok = test_server:app_test(os_mon), + ok. + +config(suite) -> + []; +config(doc) -> + ["Test OS_Mon configuration"]; +config(Config) when is_list(Config) -> + + IsReg = fun(Name) -> is_pid(whereis(Name)) end, + IsNotReg = fun(Name) -> undefined == whereis(Name) end, + + ?line ok = application:start(os_mon), + ?line true = lists:all(IsReg, [cpu_sup, disksup, memsup]), + ?line ok = application:stop(os_mon), + + ?line ok = application:set_env(os_mon, start_cpu_sup, false), + ?line ok = application:start(os_mon), + ?line true = lists:all(IsReg, [disksup, memsup]), + ?line true = IsNotReg(cpu_sup), + ?line ok = application:stop(os_mon), + ?line ok = application:set_env(os_mon, start_cpu_sup, true), + + ?line ok = application:set_env(os_mon, start_disksup, false), + ?line ok = application:start(os_mon), + ?line true = lists:all(IsReg, [cpu_sup, memsup]), + ?line true = IsNotReg(disksup), + ?line ok = application:stop(os_mon), + ?line ok = application:set_env(os_mon, start_disksup, true), + + ?line ok = application:set_env(os_mon, start_memsup, false), + ?line ok = application:start(os_mon), + ?line true = lists:all(IsReg, [cpu_sup, disksup]), + ?line true = IsNotReg(memsup), + ?line ok = application:stop(os_mon), + ?line ok = application:set_env(os_mon, start_memsup, true), + + ok. diff --git a/lib/os_mon/test/os_mon_conf.erl b/lib/os_mon/test/os_mon_conf.erl new file mode 100644 index 0000000000..5c1fa43047 --- /dev/null +++ b/lib/os_mon/test/os_mon_conf.erl @@ -0,0 +1,28 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(os_mon_conf). +-export([init/1,fin/1]). + +init(Conf) -> + RetVal = application:start(os_mon,temporary), + [{os_mon,RetVal}|Conf]. + +fin(Conf) -> + application:stop(os_mon), + lists:keydelete(os_mon,1,Conf). diff --git a/lib/os_mon/test/os_mon_mib_SUITE.erl b/lib/os_mon/test/os_mon_mib_SUITE.erl new file mode 100644 index 0000000000..a1d463030a --- /dev/null +++ b/lib/os_mon/test/os_mon_mib_SUITE.erl @@ -0,0 +1,746 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(os_mon_mib_SUITE). + +%-define(STANDALONE,1). + +-ifdef(STANDALONE). +-define(line,erlang:display({line,?LINE}),). +-define(config(A,B), config(A,B)). +-else. +-include("test_server.hrl"). +-include_lib("os_mon/include/OTP-OS-MON-MIB.hrl"). +-include_lib("snmp/include/snmp_types.hrl"). +-endif. + +% Test server specific exports +-export([all/1, init_per_suite/1, end_per_suite/1, + init_per_testcase/2, end_per_testcase/2]). + + +% Test cases must be exported. +-export([update_load_table/1]). + +-export([get_mem_sys_mark/1, get_mem_proc_mark/1, get_disk_threshold/1, + get_load_table/1, get_next_load_table/1, get_disk_table/1, + get_next_disk_table/1, real_snmp_request/1, load_unload/1]). + +-export([sys_tot_mem/1, sys_used_mem/1, large_erl_process/1, + large_erl_process_mem/1, cpu_load/1, cpu_load5/1, cpu_load15/1, + os_wordsize/1, sys_tot_mem64/1, sys_used_mem64/1, + large_erl_process_mem64/1, disk_descr/1, disk_kbytes/1, + disk_capacity/1]). + +-export([tickets/1]). +-export([otp_6351/1, otp_7441/1]). + +-define(TRAP_UDP, 5000). +-define(AGENT_UDP, 4000). +-define(CONF_FILE_VER, [v2]). +-define(SYS_NAME, "Test os_mon_mibs"). +-define(MAX_MSG_SIZE, 484). +-define(ENGINE_ID, "mgrEngine"). +-define(MGR_PORT, 5001). + +%%--------------------------------------------------------------------- +-ifdef(STANDALONE). +-export([run/0]). +run() -> + catch init_per_suite([]), + Ret = (catch update_load_table([])), + catch end_per_suite([]), + Ret. +-else. + +init_per_testcase(_Case, Config) when is_list(Config) -> + Dog = test_server:timetrap(test_server:minutes(6)), + [{watchdog, Dog}|Config]. + +end_per_testcase(_Case, Config) when is_list(Config) -> + Dog = ?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + Config. + +all(doc) -> + ["Test os_mon mibs and provided instrumentation functions."]; + +all(suite) -> + [load_unload, get_mem_sys_mark, get_mem_proc_mark, + get_disk_threshold, get_load_table, get_next_load_table, + get_disk_table, get_next_disk_table, real_snmp_request, + update_load_table, tickets]. + +tickets(suite) -> + [otp_6351, otp_7441]. + +-endif. +%%--------------------------------------------------------------------- +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initiation before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + ?line application:start(sasl), + ?line application:start(mnesia), + ?line application:start(os_mon), + + %% Create initial configuration data for the snmp application + ?line PrivDir = ?config(priv_dir, Config), + ?line ConfDir = filename:join(PrivDir, "conf"), + ?line DbDir = filename:join(PrivDir,"db"), + ?line MgrDir = filename:join(PrivDir,"mgr"), + + ?line file:make_dir(ConfDir), + ?line file:make_dir(DbDir), + ?line file:make_dir(MgrDir), + + {ok, HostName} = inet:gethostname(), + {ok, Addr} = inet:getaddr(HostName, inet), + + ?line snmp_config:write_agent_snmp_files(ConfDir, ?CONF_FILE_VER, + tuple_to_list(Addr), ?TRAP_UDP, + tuple_to_list(Addr), + ?AGENT_UDP, ?SYS_NAME), + + ?line snmp_config:write_manager_snmp_files(MgrDir, tuple_to_list(Addr), + ?MGR_PORT, ?MAX_MSG_SIZE, + ?ENGINE_ID, [], [], []), + + %% To make sure application:set_env is not overwritten by any + %% app-file settings. + ?line ok = application:load(snmp), + + ?line application:set_env(snmp, agent, [{db_dir, DbDir}, + {config, [{dir, ConfDir}]}, + {agent_type, master}, + {agent_verbosity, trace}, + {net_if, [{verbosity, trace}]}]), + ?line application:set_env(snmp, manager, [{config, [{dir, MgrDir}, + {db_dir, MgrDir}, + {verbosity, trace}]}, + {server, [{verbosity, trace}]}, + {net_if, [{verbosity, trace}]}, + {versions, [v1, v2, v3]}]), + application:start(snmp), + + %% Load the mibs that should be tested + otp_mib:load(snmp_master_agent), + os_mon_mib:load(snmp_master_agent), + + [{agent_ip, Addr}| Config]. +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(Config) -> + PrivDir = ?config(priv_dir, Config), + ConfDir = filename:join(PrivDir,"conf"), + DbDir = filename:join(PrivDir,"db"), + MgrDir = filename:join(PrivDir, "mgr"), + + %% Uload mibs + snmpa:unload_mibs(snmp_master_agent,["OTP-OS-MON-MIB"]), + otp_mib:unload(snmp_master_agent), + + %% Clean up + application:stop(snmp), + application:stop(mnesia), + application:stop(os_mon), + + del_dir(ConfDir), + del_dir(DbDir), + (catch del_dir(MgrDir)), + ok. + +%%--------------------------------------------------------------------- +%% Test cases +%%--------------------------------------------------------------------- +load_unload(doc) -> + ["Test to unload and the reload the OTP.mib "]; +load_unload(suite) -> []; +load_unload(Config) when list(Config) -> + ?line os_mon_mib:unload(snmp_master_agent), + ?line os_mon_mib:load(snmp_master_agent), + ok. +%%--------------------------------------------------------------------- + +update_load_table(doc) -> + ["check os_mon_mib:update_load_table error handling"]; +update_load_table(suite) -> + []; +update_load_table(Config) when is_list(Config) -> + ?line Node = start_node(), + ?line ok = rpc:call(Node,application,start,[sasl]), + ?line ok = rpc:call(Node,application,start,[os_mon]), + ?line ok = os_mon_mib:update_load_table(), + ?line rpc:call(Node,application,stop,[os_mon]), + ?line ok = os_mon_mib:update_load_table(), + ?line stop_node(Node), + ok. + +otp_6351(doc) -> + ["like update_load_table, when memsup_system_only==true"]; +otp_6351(suite) -> + []; +otp_6351(Config) when is_list(Config) -> + ?line Node = start_node(), + ?line ok = rpc:call(Node,application,start,[sasl]), + ?line ok = rpc:call(Node,application,load,[os_mon]), + ?line ok = rpc:call(Node,application,set_env, + [os_mon,memsup_system_only,true]), + ?line ok = rpc:call(Node,application,start,[os_mon]), + ?line Res = rpc:call(Node,os_mon_mib,get_load,[Node]), + if + is_tuple(Res), element(1, Res)==loadTable -> + ?line ok; + true -> + ?line ?t:fail(Res) + end, + ?line rpc:call(Node,application,stop,[os_mon]), + ?line stop_node(Node), + ok. + + + + +%%--------------------------------------------------------------------- +get_mem_sys_mark(doc) -> + ["Simulates a get call to test the instrumentation function " + "for the loadMemorySystemWatermark variable."]; +get_mem_sys_mark(suite) -> + []; +get_mem_sys_mark(Config) when is_list(Config) -> + case os_mon_mib:mem_sys_mark(get) of + {value, SysMark} when is_integer(SysMark) -> + ok; + _ -> + ?line test_server:fail(sys_mark_value_not_integer) + end. +%%--------------------------------------------------------------------- +get_mem_proc_mark(doc) -> + ["Simulates a get call to test the instrumentation function " + "for the loadMemoryErlProcWatermark variable."]; +get_mem_proc_mark(suite) -> + []; +get_mem_proc_mark(Config) when is_list(Config) -> + case os_mon_mib:mem_proc_mark(get) of + {value, ProcMark} when is_integer(ProcMark) -> + ok; + _ -> + ?line test_server:fail(proc_mark_value_not_integer) + end. +%%--------------------------------------------------------------------- +get_disk_threshold(doc) -> + ["Simulates a get call to test the instrumentation function " + "for the diskAlmostFullThreshold variable."]; +get_disk_threshold(suite) -> + []; +get_disk_threshold(Config) when is_list(Config) -> + case os_mon_mib:disk_threshold(get) of + {value, ProcMark} when is_integer(ProcMark) -> + ok; + _ -> + ?line test_server:fail(disk_threshold_value_not_integer) + end. +%%--------------------------------------------------------------------- + +%%% Note that when we have a string key, as in loadTable, the +%%% instrumentation will deal with the [length(String), String]. We +%%% have to know about this, when short cutting SNMP and calling +%%% instrumentation functions directly as done in most test cases in +%%% this test suite + +get_load_table(doc) -> + ["Simulates get calls to test the instrumentation function " + "for the loadTable"]; +get_load_table(suite) -> + []; +get_load_table(Config) when is_list(Config) -> + + NodeStr = atom_to_list(node()), + NodeLen = length(NodeStr), + + {_, _, {Pid, _}} = memsup:get_memory_data(), + PidStr = lists:flatten(io_lib:format("~w", [Pid])), + ?line [{value, NodeStr},{value, PidStr}] = + os_mon_mib:load_table(get, [NodeLen | NodeStr], + [?loadErlNodeName, ?loadLargestErlProcess]), + + ?line Values = os_mon_mib:load_table(get, [NodeLen | NodeStr] , + [?loadSystemTotalMemory, + ?loadSystemUsedMemory, + ?loadLargestErlProcessUsedMemory, + ?loadCpuLoad, + ?loadCpuLoad5, + ?loadCpuLoad15, + ?loadOsWordsize, + ?loadSystemTotalMemory64, + ?loadSystemUsedMemory64, + ?loadLargestErlProcessUsedMemory64]), + + IsInt = fun({value, Val}) when is_integer(Val) -> + true; + (_) -> + false + end, + + NewValues = lists:filter(IsInt, Values), + + case length(NewValues) of + 10 -> + ok; + _ -> + ?line test_server:fail(value_not_integer) + end, + + ?line [{noValue,noSuchInstance}, {noValue,noSuchInstance}, + {noValue,noSuchInstance}, {noValue,noSuchInstance}, + {noValue,noSuchInstance}, {noValue,noSuchInstance}, + {noValue,noSuchInstance}, {noValue,noSuchInstance}, + {noValue,noSuchInstance}, {noValue,noSuchInstance}, + {noValue,noSuchInstance}, {noValue,noSuchInstance}] = + os_mon_mib:load_table(get, [3, 102, 111, 111], + [?loadErlNodeName, + ?loadSystemTotalMemory, + ?loadSystemUsedMemory, + ?loadLargestErlProcess, + ?loadLargestErlProcessUsedMemory, + ?loadCpuLoad, + ?loadCpuLoad5, + ?loadCpuLoad15, + ?loadOsWordsize, + ?loadSystemTotalMemory64, + ?loadSystemUsedMemory64, + ?loadLargestErlProcessUsedMemory64]), + + ok. +%%--------------------------------------------------------------------- +get_next_load_table(doc) -> + ["Simulates get_next calls to test the instrumentation function " + "for the loadTable"]; +get_next_load_table(suite) -> + [ sys_tot_mem, + sys_used_mem, + large_erl_process, + large_erl_process_mem, + cpu_load, + cpu_load5, + cpu_load15, + os_wordsize, + sys_tot_mem64, + sys_used_mem64, + large_erl_process_mem64]. + +sys_tot_mem(doc) -> + []; +sys_tot_mem(suite) -> + []; +sys_tot_mem(Config) when is_list(Config) -> + ?line [{[?loadSystemTotalMemory, Len | NodeStr], Mem}] = + os_mon_mib:load_table(get_next, [], [?loadSystemTotalMemory]), + ?line Len = length(NodeStr), + ?line true = lists:member(list_to_atom(NodeStr), [node() | nodes()]), + + case Mem of + Mem when is_integer(Mem) -> + ok; + _ -> + ?line test_server:fail(sys_tot_mem_value_not_integer) + end. + +sys_used_mem(doc) -> + []; +sys_used_mem(suite) -> []; +sys_used_mem(Config) when is_list(Config) -> + ?line [{[?loadSystemUsedMemory, Len | NodeStr], Mem}] = + os_mon_mib:load_table(get_next,[], [?loadSystemUsedMemory]), + ?line Len = length(NodeStr), + ?line true = lists:member(list_to_atom(NodeStr), [node() | nodes()]), + + case Mem of + Mem when is_integer(Mem) -> + ok; + _ -> + ?line test_server:fail(sys_used_mem_value_not_integer) + end. + +large_erl_process(doc) -> + []; +large_erl_process(suite) -> + []; +large_erl_process(Config) when is_list(Config) -> + {_, _, {Pid, _}} = memsup:get_memory_data(), + PidStr = lists:flatten(io_lib:format("~w", [Pid])), + ?line [{[?loadLargestErlProcess, Len | NodeStr], PidStr}] = + os_mon_mib:load_table(get_next,[], [?loadLargestErlProcess]), + ?line Len = length(NodeStr), + ?line true = lists:member(list_to_atom(NodeStr), [node() | nodes()]), + ok. + +large_erl_process_mem(doc) -> + []; +large_erl_process_mem(suite) -> + []; +large_erl_process_mem(Config) when is_list(Config) -> + + ?line [{[?loadLargestErlProcessUsedMemory, Len | NodeStr], Mem}] = + os_mon_mib:load_table(get_next,[], + [?loadLargestErlProcessUsedMemory]), + ?line Len = length(NodeStr), + ?line true = lists:member(list_to_atom(NodeStr), [node() | nodes()]), + + case Mem of + Mem when is_integer(Mem) -> + ok; + _ -> + ?line test_server:fail(erl_pid_mem_value_not_integer) + end. + +cpu_load(doc) -> + []; +cpu_load(suite) -> + []; +cpu_load(Config) when list(Config) -> + ?line [{[?loadCpuLoad, Len | NodeStr], Load}] = + os_mon_mib:load_table(get_next,[], [?loadCpuLoad]), + ?line Len = length(NodeStr), + ?line true = lists:member(list_to_atom(NodeStr), [node() | nodes()]), + + case Load of + Load when is_integer(Load) -> + ok; + _ -> + ?line test_server:fail(cpu_load_value_not_integer) + end. + +cpu_load5(doc) -> + []; +cpu_load5(suite) -> + []; +cpu_load5(Config) when is_list(Config) -> + ?line [{[?loadCpuLoad5, Len | NodeStr], Load}] = + os_mon_mib:load_table(get_next,[], [?loadCpuLoad5]), + ?line Len = length(NodeStr), + ?line true = lists:member(list_to_atom(NodeStr), [node() | nodes()]), + + case Load of + Load when is_integer(Load) -> + ok; + _ -> + ?line test_server:fail(cpu_load5_value_not_integer) + end. + +cpu_load15(doc) -> + []; +cpu_load15(suite) -> + []; +cpu_load15(Config) when is_list(Config) -> + ?line [{[?loadCpuLoad15, Len | NodeStr], Load}] = + os_mon_mib:load_table(get_next,[], [?loadCpuLoad15]), + ?line Len = length(NodeStr), + ?line true = lists:member(list_to_atom(NodeStr), [node() | nodes()]), + + case Load of + Load when is_integer(Load) -> + ok; + _ -> + ?line test_server:fail(cpu_load15_value_not_integer) + end. + +os_wordsize(doc) -> + []; +os_wordsize(suite) -> + []; +os_wordsize(Config) when is_list(Config) -> + ?line [{[?loadOsWordsize, Len | NodeStr], Wordsize}] = + os_mon_mib:load_table(get_next,[], [?loadOsWordsize]), + ?line Len = length(NodeStr), + ?line true = lists:member(list_to_atom(NodeStr), [node() | nodes()]), + + case Wordsize of + Wordsize when is_integer(Wordsize) -> + ok; + _ -> + ?line test_server:fail(os_wordsize_value_not_integer) + end. + +sys_tot_mem64(doc) -> + []; +sys_tot_mem64(suite) -> + []; +sys_tot_mem64(Config) when is_list(Config) -> + ?line [{[?loadSystemTotalMemory64, Len | NodeStr], Mem}] = + os_mon_mib:load_table(get_next, [], [?loadSystemTotalMemory64]), + ?line Len = length(NodeStr), + ?line true = lists:member(list_to_atom(NodeStr), [node() | nodes()]), + + case Mem of + Mem when is_integer(Mem) -> + ok; + _ -> + ?line test_server:fail(sys_tot_mem_value_not_integer) + end. + +sys_used_mem64(doc) -> + []; +sys_used_mem64(suite) -> []; +sys_used_mem64(Config) when is_list(Config) -> + ?line [{[?loadSystemUsedMemory64, Len | NodeStr], Mem}] = + os_mon_mib:load_table(get_next,[], [?loadSystemUsedMemory64]), + ?line Len = length(NodeStr), + ?line true = lists:member(list_to_atom(NodeStr), [node() | nodes()]), + + case Mem of + Mem when is_integer(Mem) -> + ok; + _ -> + ?line test_server:fail(sys_used_mem_value_not_integer) + end. + +large_erl_process_mem64(doc) -> + []; +large_erl_process_mem64(suite) -> + []; +large_erl_process_mem64(Config) when is_list(Config) -> + + ?line [{[?loadLargestErlProcessUsedMemory64, Len | NodeStr], Mem}] = + os_mon_mib:load_table(get_next,[], + [?loadLargestErlProcessUsedMemory64]), + ?line Len = length(NodeStr), + ?line true = lists:member(list_to_atom(NodeStr), [node() | nodes()]), + + case Mem of + Mem when is_integer(Mem) -> + ok; + _ -> + ?line test_server:fail(erl_pid_mem_value_not_integer) + end. +%%--------------------------------------------------------------------- +get_disk_table(doc) -> + ["Simulates get calls to test the instrumentation function " + "for the diskTable."]; +get_disk_table(suite) -> + []; +get_disk_table(Config) when is_list(Config) -> + + DiskData = disksup:get_disk_data(), + DiskDataLen = length(DiskData), + + if + DiskDataLen > 0 -> + ?line [{value, Value}] = + os_mon_mib:disk_table(get, [1,1], [?diskDescr]), + + case is_list(Value) of + true -> + ok; + false -> + ?line test_server:fail(value_not_a_string) + end, + + ?line Values = os_mon_mib:disk_table(get, [1,1], + [?diskId, + ?diskKBytes, + ?diskCapacity]), + + IsInt = fun({value, Val}) when is_integer(Val) -> + true; + (_) -> + false + end, + + NewValues = lists:filter(IsInt, Values), + + case length(NewValues) of + 3 -> + ok; + _ -> + ?line test_server:fail(value_not_integer) + end + end, + + ?line [{noValue,noSuchInstance}, {noValue,noSuchInstance}, + {noValue,noSuchInstance}, {noValue,noSuchInstance}] = + os_mon_mib:disk_table(get, [1, DiskDataLen + 1], [?diskId, + ?diskDescr, + ?diskKBytes, + ?diskCapacity]), + + ok. + +%%--------------------------------------------------------------------- +get_next_disk_table(doc) -> + ["Simulates get_next calls to test the instrumentation function " + "for the diskTable."]; +get_next_disk_table(suite) -> + [disk_descr, disk_kbytes, disk_capacity]. + +disk_descr(doc) -> + []; +disk_descr(suite) -> + []; +disk_descr(Config) when is_list(Config) -> + ?line [{[?diskDescr, 1,1], Descr}] = + os_mon_mib:disk_table(get_next, [], [?diskDescr]), + + case Descr of + Descr when is_list(Descr) -> + ok; + _ -> + ?line test_server:fail(disk_descr_value_not_a_string) + end. + +disk_kbytes(doc) -> + []; +disk_kbytes(suite) -> []; +disk_kbytes(Config) when is_list(Config) -> + ?line [{[?diskKBytes, 1,1], Kbytes}] = + os_mon_mib:disk_table(get_next,[], [?diskKBytes]), + + case Kbytes of + Kbytes when is_integer(Kbytes) -> + ok; + _ -> + ?line test_server:fail(disk_kbytes_value_not_integer) + end. + + +disk_capacity(doc) -> + []; +disk_capacity(suite) -> []; +disk_capacity(Config) when is_list(Config) -> + ?line [{[?diskCapacity, 1,1], Capacity}] = + os_mon_mib:disk_table(get_next,[], [?diskCapacity]), + + case Capacity of + Capacity when is_integer(Capacity) -> + ok; + _ -> + ?line test_server:fail(disk_capacity_value_not_integer) + end. + +%%--------------------------------------------------------------------- +real_snmp_request(doc) -> + ["Starts an snmp manager and sends a real snmp-reques. i.e. " + "sends a udp message on the correct format."]; +real_snmp_request(suite) -> []; +real_snmp_request(Config) when list(Config) -> + Agent_ip = ?config(agent_ip, Config), + + ?line ok = snmpm:register_user(os_mon_mib_test, snmpm_user_default, []), + ?line ok = snmpm:register_agent(os_mon_mib_test, Agent_ip, ?AGENT_UDP), + + NodStr = atom_to_list(node()), + Len = length(NodStr), + {_, _, {Pid, _}} = memsup:get_memory_data(), + PidStr = lists:flatten(io_lib:format("~w", [Pid])), + io:format("FOO: ~p~n", [PidStr]), + ?line ok = snmp_get(Agent_ip, + [?loadEntry ++ + [?loadLargestErlProcess, Len | NodStr]], + PidStr), + ?line ok = snmp_get_next(Agent_ip, + [?loadEntry ++ + [?loadSystemUsedMemory, Len | NodStr]], + ?loadEntry ++ [?loadSystemUsedMemory + 1, Len + | NodStr], PidStr), + ?line ok = snmp_set(Agent_ip, [?loadEntry ++ + [?loadLargestErlProcess, Len | NodStr]], + s, "<0.101.0>"), + ok. + +otp_7441(doc) -> + ["Starts an snmp manager and requests total memory. Was previously + integer32 which was errornous on 64 bit machines."]; +otp_7441(suite) -> + []; +otp_7441(Config) when is_list(Config) -> + Agent_ip = ?config(agent_ip, Config), + + + NodStr = atom_to_list(node()), + Len = length(NodStr), + Oids = [Oid|_] = [?loadEntry ++ [?loadSystemTotalMemory, Len | NodStr]], + ?line { ok, {noError,0,[#varbind{oid = Oid, variabletype = 'Unsigned32'}]}, _} = + snmpm:g(os_mon_mib_test, Agent_ip, ?AGENT_UDP, Oids), + + ok. + +%%--------------------------------------------------------------------- +%% Internal functions +%%--------------------------------------------------------------------- +-ifdef(STANDALONE). +config(priv_dir,_) -> + "/tmp". + +start_node() -> + Host = hd(tl(string:tokens(atom_to_list(node()),"@"))), + {ok,Node} = slave:start(Host,testnisse), + net_adm:ping(testnisse), + Node. + + +stop_node(Node) -> + rpc:call(Node,erlang,halt,[]). +-else. +start_node() -> + ?line Pa = filename:dirname(code:which(?MODULE)), + ?line {ok,Node} = test_server:start_node(testnisse, slave, + [{args, " -pa " ++ Pa}]), + Node. + +stop_node(Node) -> + test_server:stop_node(Node). + +-endif. + +del_dir(Dir) -> + io:format("Deleting: ~s~n",[Dir]), + {ok, Files} = file:list_dir(Dir), + FullPathFiles = lists:map(fun(File) -> filename:join(Dir, File) end, + Files), + lists:foreach({file, delete}, FullPathFiles), + file:del_dir(Dir). + +%%--------------------------------------------------------------------- +snmp_get(Agent_ip, Oids = [Oid |_], Result) -> + ?line {ok,{noError,0,[#varbind{oid = Oid, + variabletype = 'OCTET STRING', + value = Result}]}, _} = + snmpm:g(os_mon_mib_test, Agent_ip, ?AGENT_UDP, Oids), + ok. + +snmp_get_next(Agent_ip, Oids, NextOid, Result) -> + ?line {ok,{noError,0,[#varbind{oid = NextOid, + variabletype = 'OCTET STRING', + value = Result}]},_} = + snmpm:gn(os_mon_mib_test, Agent_ip, ?AGENT_UDP, Oids), + ok. + +snmp_set(Agent_ip, Oid, ValuType, Value) -> + ?line {ok, {notWritable, _, _}, _} = + snmpm:s(os_mon_mib_test,Agent_ip,?AGENT_UDP,[{Oid, ValuType, Value}]), + ok. diff --git a/lib/os_mon/test/os_sup_SUITE.erl b/lib/os_mon/test/os_sup_SUITE.erl new file mode 100644 index 0000000000..25041f968d --- /dev/null +++ b/lib/os_mon/test/os_sup_SUITE.erl @@ -0,0 +1,189 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(os_sup_SUITE). +-include("test_server.hrl"). + +%% Test server specific exports +-export([all/1]). +-export([init_per_suite/1, end_per_suite/1]). +-export([init_per_testcase/2, end_per_testcase/2]). + +%% Test cases +-export([message/1]). +-export([config/1, port/1]). + +%% Default timetrap timeout (set in init_per_testcase) +-define(default_timeout, ?t:minutes(1)). + +-define(TAG, test_tag). +-define(MFA, {?MODULE, test_mfa, [?TAG]}). + +-export([test_mfa/2]). + +init_per_suite(Config) when is_list(Config) -> + spawn(fun() -> message_receptor() end), + ?line application:load(os_mon), + ?line ok = application:set_env(os_mon, start_os_sup, true), + ?line ok = application:set_env(os_mon, os_sup_mfa, ?MFA), + ?line ok = application:set_env(os_mon, os_sup_enable, false), + ?line ok = application:start(os_mon), + Config. + +end_per_suite(Config) when is_list(Config) -> + ?line application:stop(os_mon), + ?line ok = application:set_env(os_mon, start_os_sup, false), + MFA = {os_sup, error_report, [std_error]}, + ?line ok = application:set_env(os_mon, os_sup_mfa, MFA), + ?line ok = application:set_env(os_mon, os_sup_enable, true), + ?line exit(whereis(message_receptor), done), + Config. + +init_per_testcase(_Case, Config) -> + Dog = ?t:timetrap(?default_timeout), + [{watchdog,Dog} | Config]. + +end_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +all(suite) -> + case ?t:os_type() of + {unix, sunos} -> + [message, config, port]; + {win32, _OSname} -> + [message]; + OS -> + Str = io_lib:format("os_sup not available for ~p", [OS]), + {skip, lists:flatten(Str)} + end. + +message(suite) -> + []; +message(doc) -> + ["Test OS message handling"]; +message(Config) when is_list(Config) -> + + %% Fake an OS message + Data = "10H11386278426HSystem4HTest5HError5HTesto", + ?line os_sup_server ! {faked_port, {data, Data}}, + + %% Check with message_receptor that it has been received + ?t:sleep(?t:seconds(1)), + Msg = + case ?t:os_type() of + {unix, sunos} -> + {?TAG, Data}; + {win32, _} -> + {?TAG,{{1138,627842,0},"System","Test","Error","Testo"}} + end, + ?line message_receptor ! {check, self(), Msg}, + receive + {result, true} -> + ok; + {result, Rec} -> + ?t:fail({no_message, Rec}) + end, + + ok. + +config(suite) -> + []; +config(doc) -> + ["Test configuration"]; +config(Config) when is_list(Config) -> + + %% os_sup_enable==true and os_sup_own/os_sup_syslogconf cannot + %% be tested as test_server is not running is root + + %% os_sup_mfa is already tested, sort of (in init_per_suite) + + %% os_sup_errortag should be tested, however + + ok. + +port(suite) -> + []; +port(doc) -> + ["Test that os_sup handles a terminating port program"]; +port(Config) when is_list(Config) -> + ?line Str = os:cmd("ps -e | grep '[f]errule'"), + case io_lib:fread("~s", Str) of + {ok, [Pid], _Rest} -> + + %% Monitor os_sup_server + ?line MonRef = erlang:monitor(process, os_sup_server), + + %% Kill the port program + case os:cmd("kill -9 " ++ Pid) of + [] -> + + %% os_sup_server should now terminate + receive + {'DOWN', MonRef, _, _, {port_died, _Reason}} -> + ok; + {'DOWN', MonRef, _, _, Reason} -> + ?line ?t:fail({unexpected_exit_reason, Reason}) + after + 3000 -> + ?line ?t:fail(still_alive) + end, + + %% Give os_mon_sup time to restart os_sup + ?t:sleep(?t:seconds(3)), + ?line true = is_pid(whereis(os_sup_server)), + + ok; + + Line -> + erlang:demonitor(MonRef), + {skip, {not_killed, Line}} + end; + _ -> + {skip, {os_pid_not_found}} + end. + +%%---------------------------------------------------------------------- +%% Auxiliary +%%---------------------------------------------------------------------- + +test_mfa(Message, Tag) -> + message_receptor ! {Tag, Message}. + +message_receptor() -> + register(message_receptor, self()), + message_receptor([]). + +message_receptor(Received) -> + receive + %% Check if a certain message has been received + {check, From, Msg} -> + case lists:member(Msg, Received) of + true -> + From ! {result, true}, + message_receptor(lists:delete(Msg, Received)); + false -> + From ! {result, Received}, + message_receptor(Received) + end; + + %% Save all other messages + Msg -> + message_receptor([Msg|Received]) + end. diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl index 6503321042..82681502ab 100644 --- a/lib/public_key/include/public_key.hrl +++ b/lib/public_key/include/public_key.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% Copyright Ericsson AB 2008-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -28,6 +28,13 @@ algorithm, parameters = asn1_NOVALUE}). +-define(DEFAULT_VERIFYFUN, + {fun(_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState} + end, []}). + -record(path_validation_state, { valid_policy_tree, explicit_policy, @@ -42,7 +49,7 @@ working_public_key_parameters, working_issuer_name, max_path_length, - acc_errors, %% If verify_none option is set + verify_fun, user_state }). diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl index 64fc8ab5bc..b3c230df25 100644 --- a/lib/public_key/src/pubkey_cert.erl +++ b/lib/public_key/src/pubkey_cert.erl @@ -27,7 +27,6 @@ validate_time/3, validate_signature/6, validate_issuer/4, validate_names/6, validate_revoked_status/3, validate_extensions/4, - validate_unknown_extensions/3, normalize_general_name/1, digest_type/1, is_self_signed/1, is_issuer/2, issuer_id/2, is_fixed_dh_cert/1, verify_data/1]). @@ -68,13 +67,14 @@ init_validation_state(#'OTPCertificate'{} = OtpCert, DefaultPathLen, Options, false)), PolicyMapping = policy_indicator(MaxLen, proplists:get_value(policy_mapping, Options, false)), - AccErrors = proplists:get_value(acc_errors, Options, []), - State = #path_validation_state{max_path_length = MaxLen, - valid_policy_tree = PolicyTree, - explicit_policy = ExplicitPolicy, - inhibit_any_policy = InhibitAnyPolicy, - policy_mapping = PolicyMapping, - acc_errors = AccErrors, + {VerifyFun, UserState} = proplists:get_value(verify_fun, Options, ?DEFAULT_VERIFYFUN), + State = #path_validation_state{max_path_length = MaxLen, + valid_policy_tree = PolicyTree, + explicit_policy = ExplicitPolicy, + inhibit_any_policy = InhibitAnyPolicy, + policy_mapping = PolicyMapping, + verify_fun = VerifyFun, + user_state = UserState, cert_num = 0}, prepare_for_next_cert(OtpCert, State). @@ -112,12 +112,12 @@ prepare_for_next_cert(OtpCert, ValidationState = #path_validation_state{ }. %%-------------------------------------------------------------------- --spec validate_time(#'OTPCertificate'{}, list(), boolean()) -> list(). +-spec validate_time(#'OTPCertificate'{}, term(), fun()) -> term(). %% %% Description: Check that the certificate validity period includes the %% current time. %%-------------------------------------------------------------------- -validate_time(OtpCert, AccErr, Verify) -> +validate_time(OtpCert, UserState, VerifyFun) -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, {'Validity', NotBeforeStr, NotAfterStr} = TBSCert#'OTPTBSCertificate'.validity, @@ -127,27 +127,27 @@ validate_time(OtpCert, AccErr, Verify) -> case ((NotBefore =< Now) and (Now =< NotAfter)) of true -> - AccErr; + UserState; false -> - not_valid({bad_cert, cert_expired}, Verify, AccErr) + verify_fun(OtpCert, {bad_cert, cert_expired}, UserState, VerifyFun) end. %%-------------------------------------------------------------------- --spec validate_issuer(#'OTPCertificate'{}, term(), list(), boolean()) -> list(). +-spec validate_issuer(#'OTPCertificate'{}, term(), term(), fun()) -> term(). %% %% Description: Check that the certificate issuer name is the working_issuer_name %% in path_validation_state. %%-------------------------------------------------------------------- -validate_issuer(OtpCert, Issuer, AccErr, Verify) -> +validate_issuer(OtpCert, Issuer, UserState, VerifyFun) -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, case is_issuer(Issuer, TBSCert#'OTPTBSCertificate'.issuer) of true -> - AccErr; + UserState; _ -> - not_valid({bad_cert, invalid_issuer}, Verify, AccErr) + verify_fun(OtpCert, {bad_cert, invalid_issuer}, UserState, VerifyFun) end. %%-------------------------------------------------------------------- -spec validate_signature(#'OTPCertificate'{}, der_encoded(), - term(),term(), list(), boolean()) -> list(). + term(),term(), term(), fun()) -> term(). %% %% Description: Check that the signature on the certificate can be verified using @@ -155,24 +155,24 @@ validate_issuer(OtpCert, Issuer, AccErr, Verify) -> %% the working_public_key_parameters in path_validation_state. %%-------------------------------------------------------------------- validate_signature(OtpCert, DerCert, Key, KeyParams, - AccErr, Verify) -> + UserState, VerifyFun) -> case verify_signature(OtpCert, DerCert, Key, KeyParams) of true -> - AccErr; + UserState; false -> - not_valid({bad_cert, invalid_signature}, Verify, AccErr) + verify_fun(OtpCert, {bad_cert, invalid_signature}, UserState, VerifyFun) end. %%-------------------------------------------------------------------- -spec validate_names(#'OTPCertificate'{}, list(), list(), - term(), list(), boolean())-> list(). + term(), term(), fun())-> term(). %% %% Description: Validate Subject Alternative Name. %%-------------------------------------------------------------------- -validate_names(OtpCert, Permit, Exclude, Last, AccErr, Verify) -> +validate_names(OtpCert, Permit, Exclude, Last, UserState, VerifyFun) -> case is_self_signed(OtpCert) andalso (not Last) of true -> - AccErr; + UserState; false -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, Subject = TBSCert#'OTPTBSCertificate'.subject, @@ -196,51 +196,36 @@ validate_names(OtpCert, Permit, Exclude, Last, AccErr, Verify) -> (not is_excluded(Name, Exclude)) andalso (not is_excluded(AltNames, Exclude))) of true -> - AccErr; + UserState; false -> - not_valid({bad_cert, name_not_permitted}, - Verify, AccErr) + verify_fun(OtpCert, {bad_cert, name_not_permitted}, + UserState, VerifyFun) end end. %%-------------------------------------------------------------------- --spec validate_revoked_status(#'OTPCertificate'{}, boolean(), list()) -> - list(). +-spec validate_revoked_status(#'OTPCertificate'{}, term(), fun()) -> + term(). %% %% Description: Check if certificate has been revoked. %%-------------------------------------------------------------------- -validate_revoked_status(_OtpCert, _Verify, AccErr) -> +validate_revoked_status(_OtpCert, UserState, _VerifyFun) -> %% TODO: Implement or leave for application?! - %% true | + %% valid | %% throw({bad_cert, cert_revoked}) - AccErr. + UserState. %%-------------------------------------------------------------------- -spec validate_extensions(#'OTPCertificate'{}, #path_validation_state{}, - boolean(), list())-> - {#path_validation_state{}, - UnknownExtensions :: list(), AccErrors :: list()}. + term(), fun())-> + {#path_validation_state{}, UserState :: term()}. %% %% Description: Check extensions included in basic path validation. %%-------------------------------------------------------------------- -validate_extensions(OtpCert, ValidationState, Verify, AccErr) -> +validate_extensions(OtpCert, ValidationState, UserState, VerifyFun) -> TBSCert = OtpCert#'OTPCertificate'.tbsCertificate, Extensions = TBSCert#'OTPTBSCertificate'.extensions, - validate_extensions(Extensions, ValidationState, no_basic_constraint, - is_self_signed(OtpCert), [], Verify, AccErr). - -%-------------------------------------------------------------------- - -spec validate_unknown_extensions(list(), list(), boolean())-> list(). -%% -%% Description: Check that all critical extensions has been handled. -%%-------------------------------------------------------------------- -validate_unknown_extensions([], AccErr, _Verify) -> - AccErr; -validate_unknown_extensions([#'Extension'{critical = true} | _], - AccErr, Verify) -> - not_valid({bad_cert, unknown_critical_extension}, Verify, AccErr); -validate_unknown_extensions([#'Extension'{critical = false} | Rest], - AccErr, Verify) -> - validate_unknown_extensions(Rest, AccErr, Verify). + validate_extensions(OtpCert, Extensions, ValidationState, no_basic_constraint, + is_self_signed(OtpCert), UserState, VerifyFun). %%-------------------------------------------------------------------- -spec normalize_general_name({rdnSequence, term()}) -> {rdnSequence, term()}. @@ -330,10 +315,25 @@ extensions_list(asn1_NOVALUE) -> extensions_list(Extensions) -> Extensions. -not_valid(Error, true, _) -> - throw(Error); -not_valid(Error, false, AccErrors) -> - [Error | AccErrors]. +verify_fun(Otpcert, Result, UserState0, VerifyFun) -> + case VerifyFun(Otpcert, Result, UserState0) of + {valid,UserState} -> + UserState; + {fail, Reason} -> + case Result of + {bad_cert, _} -> + throw(Result); + _ -> + throw({bad_cert, Reason}) + end; + {unknown, UserState} -> + case Result of + {extension, #'Extension'{critical = true}} -> + throw({bad_cert, unknown_critical_extension}); + _ -> + UserState + end + end. extract_verify_data(OtpCert, DerCert) -> {0, Signature} = OtpCert#'OTPCertificate'.signature, @@ -460,198 +460,189 @@ select_extension(Id, [_ | Extensions]) -> select_extension(Id, Extensions). %% No extensions present -validate_extensions(asn1_NOVALUE, ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr) -> - validate_extensions([], ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr); - -validate_extensions([], ValidationState, basic_constraint, _SelfSigned, - UnknownExtensions, _Verify, AccErr) -> - {ValidationState, UnknownExtensions, AccErr}; -validate_extensions([], ValidationState = - #path_validation_state{max_path_length = Len, - last_cert = Last}, - no_basic_constraint, SelfSigned, UnknownExtensions, - Verify, AccErr0) -> +validate_extensions(OtpCert, asn1_NOVALUE, ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun) -> + validate_extensions(OtpCert, [], ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun); + +validate_extensions(_,[], ValidationState, basic_constraint, _SelfSigned, + UserState, _) -> + {ValidationState, UserState}; +validate_extensions(OtpCert, [], ValidationState = + #path_validation_state{max_path_length = Len, + last_cert = Last}, + no_basic_constraint, SelfSigned, UserState0, VerifyFun) -> case Last of true when SelfSigned -> - {ValidationState, UnknownExtensions, AccErr0}; + {ValidationState, UserState0}; true -> {ValidationState#path_validation_state{max_path_length = Len - 1}, - UnknownExtensions, AccErr0}; + UserState0}; %% basic_constraint must appear in certs used for digital sign %% see 4.2.1.10 in rfc 3280 false -> - AccErr = not_valid({bad_cert, missing_basic_constraint}, - Verify, AccErr0), + UserState = verify_fun(OtpCert, {bad_cert, missing_basic_constraint}, + UserState0, VerifyFun), case SelfSigned of true -> - {ValidationState, UnknownExtensions, AccErr}; + {ValidationState, UserState}; false -> {ValidationState#path_validation_state{max_path_length = - Len - 1}, - UnknownExtensions, AccErr} + Len - 1}, + UserState} end end; -validate_extensions([#'Extension'{extnID = ?'id-ce-basicConstraints', +validate_extensions(OtpCert, + [#'Extension'{extnID = ?'id-ce-basicConstraints', extnValue = - #'BasicConstraints'{cA = true, - pathLenConstraint = N}} | + #'BasicConstraints'{cA = true, + pathLenConstraint = N}} | Rest], - ValidationState = - #path_validation_state{max_path_length = Len}, _, - SelfSigned, UnknownExtensions, Verify, AccErr) -> + ValidationState = + #path_validation_state{max_path_length = Len}, _, + SelfSigned, UserState, VerifyFun) -> Length = if SelfSigned -> erlang:min(N, Len); true -> erlang:min(N, Len-1) end, - validate_extensions(Rest, + validate_extensions(OtpCert, Rest, ValidationState#path_validation_state{max_path_length = - Length}, - basic_constraint, SelfSigned, UnknownExtensions, - Verify, AccErr); + Length}, + basic_constraint, SelfSigned, + UserState, VerifyFun); %% The pathLenConstraint field is meaningful only if cA is set to %% TRUE. -validate_extensions([#'Extension'{extnID = ?'id-ce-basicConstraints', - extnValue = - #'BasicConstraints'{cA = false}} | - Rest], ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr) -> - validate_extensions(Rest, ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr); - -%% -validate_extensions([#'Extension'{extnID = ?'id-ce-keyUsage', - extnValue = KeyUse - } | Rest], - #path_validation_state{last_cert=Last} = ValidationState, - ExistBasicCon, SelfSigned, UnknownExtensions, - Verify, AccErr0) -> +validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-basicConstraints', + extnValue = + #'BasicConstraints'{cA = false}} | + Rest], ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun) -> + validate_extensions(OtpCert, Rest, ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun); + +validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-keyUsage', + extnValue = KeyUse + } | Rest], + #path_validation_state{last_cert=Last} = ValidationState, + ExistBasicCon, SelfSigned, + UserState0, VerifyFun) -> case Last orelse is_valid_key_usage(KeyUse, keyCertSign) of true -> - validate_extensions(Rest, ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, - AccErr0); + validate_extensions(OtpCert, Rest, ValidationState, ExistBasicCon, + SelfSigned, UserState0, VerifyFun); false -> - AccErr = not_valid({bad_cert, invalid_key_usage}, Verify, AccErr0), - validate_extensions(Rest, ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, - AccErr) + UserState = verify_fun(OtpCert, {bad_cert, invalid_key_usage}, + UserState0, VerifyFun), + validate_extensions(OtpCert, Rest, ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun) end; -validate_extensions([#'Extension'{extnID = ?'id-ce-subjectAltName', - extnValue = Names} | Rest], - ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr0) -> +validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-subjectAltName', + extnValue = Names} | Rest], + ValidationState, ExistBasicCon, + SelfSigned, UserState0, VerifyFun) -> case validate_subject_alt_names(Names) of true when Names =/= [] -> - validate_extensions(Rest, ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, - AccErr0); + validate_extensions(OtpCert, Rest, ValidationState, ExistBasicCon, + SelfSigned, UserState0, VerifyFun); _ -> - AccErr = - not_valid({bad_cert, invalid_subject_altname}, - Verify, AccErr0), - validate_extensions(Rest, ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, - AccErr) + UserState = verify_fun(OtpCert, {bad_cert, invalid_subject_altname}, + UserState0, VerifyFun), + validate_extensions(OtpCert, Rest, ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun) end; %% This extension SHOULD NOT be marked critical. Its value %% does not have to be further validated at this point. -validate_extensions([#'Extension'{extnID = ?'id-ce-issuerAltName', - extnValue = _} | Rest], - ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr) -> - validate_extensions(Rest, ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr); +validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-issuerAltName', + extnValue = _} | Rest], + ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun) -> + validate_extensions(OtpCert, Rest, ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun); %% This extension MUST NOT be marked critical.Its value %% does not have to be further validated at this point. -validate_extensions([#'Extension'{extnID = Id, - extnValue = _, - critical = false} | Rest], +validate_extensions(OtpCert, [#'Extension'{extnID = Id, + extnValue = _, + critical = false} | Rest], ValidationState, - ExistBasicCon, SelfSigned, UnknownExtensions, - Verify, AccErr) + ExistBasicCon, SelfSigned, + UserState, VerifyFun) when Id == ?'id-ce-subjectKeyIdentifier'; Id == ?'id-ce-authorityKeyIdentifier'-> - validate_extensions(Rest, ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr); + validate_extensions(OtpCert, Rest, ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun); -validate_extensions([#'Extension'{extnID = ?'id-ce-nameConstraints', +validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-nameConstraints', extnValue = NameConst} | Rest], ValidationState, - ExistBasicCon, SelfSigned, UnknownExtensions, - Verify, AccErr) -> + ExistBasicCon, SelfSigned, UserState, VerifyFun) -> Permitted = NameConst#'NameConstraints'.permittedSubtrees, Excluded = NameConst#'NameConstraints'.excludedSubtrees, NewValidationState = add_name_constraints(Permitted, Excluded, ValidationState), - validate_extensions(Rest, NewValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr); + validate_extensions(OtpCert, Rest, NewValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun); -validate_extensions([#'Extension'{extnID = ?'id-ce-certificatePolicies', - critical = true} | Rest], ValidationState, - ExistBasicCon, SelfSigned, - UnknownExtensions, Verify, AccErr0) -> +validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-certificatePolicies', + critical = true} = Ext| Rest], ValidationState, + ExistBasicCon, SelfSigned, UserState0, VerifyFun) -> %% TODO: Remove this clause when policy handling is %% fully implemented - AccErr = - not_valid({bad_cert, unknown_critical_extension}, Verify, AccErr0), - validate_extensions(Rest, ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr); - -validate_extensions([#'Extension'{extnID = ?'id-ce-certificatePolicies', - extnValue = #'PolicyInformation'{ - policyIdentifier = Id, - policyQualifiers = Qualifier}} - | Rest], #path_validation_state{valid_policy_tree = Tree} + UserState = verify_fun(OtpCert, {extension, Ext}, + UserState0, VerifyFun), + validate_extensions(OtpCert,Rest, ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun); + +validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-certificatePolicies', + extnValue = #'PolicyInformation'{ + policyIdentifier = Id, + policyQualifiers = Qualifier}} + | Rest], #path_validation_state{valid_policy_tree = Tree} = ValidationState, - ExistBasicCon, SelfSigned, UnknownExtensions, - Verify, AccErr) -> + ExistBasicCon, SelfSigned, UserState, VerifyFun) -> %% TODO: Policy imp incomplete NewTree = process_policy_tree(Id, Qualifier, Tree), - validate_extensions(Rest, + validate_extensions(OtpCert, Rest, ValidationState#path_validation_state{ valid_policy_tree = NewTree}, - ExistBasicCon, SelfSigned, UnknownExtensions, - Verify, AccErr); + ExistBasicCon, SelfSigned, UserState, VerifyFun); -validate_extensions([#'Extension'{extnID = ?'id-ce-policyConstraints', - critical = true} | Rest], ValidationState, - ExistBasicCon, SelfSigned, UnknownExtensions, Verify, - AccErr0) -> +validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-policyConstraints', + critical = true} = Ext | Rest], ValidationState, + ExistBasicCon, SelfSigned, UserState0, VerifyFun) -> %% TODO: Remove this clause when policy handling is %% fully implemented - AccErr = - not_valid({bad_cert, unknown_critical_extension}, Verify, AccErr0), - validate_extensions(Rest, ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr); -validate_extensions([#'Extension'{extnID = ?'id-ce-policyConstraints', - extnValue = #'PolicyConstraints'{ - requireExplicitPolicy = ExpPolicy, - inhibitPolicyMapping = MapPolicy}} - | Rest], ValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr) -> + UserState = verify_fun(OtpCert, {extension, Ext}, + UserState0, VerifyFun), + validate_extensions(OtpCert, Rest, ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun); +validate_extensions(OtpCert, [#'Extension'{extnID = ?'id-ce-policyConstraints', + extnValue = #'PolicyConstraints'{ + requireExplicitPolicy = ExpPolicy, + inhibitPolicyMapping = MapPolicy}} + | Rest], ValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun) -> %% TODO: Policy imp incomplete - NewValidationState = add_policy_constraints(ExpPolicy, MapPolicy, + NewValidationState = add_policy_constraints(ExpPolicy, MapPolicy, ValidationState), - validate_extensions(Rest, NewValidationState, ExistBasicCon, - SelfSigned, UnknownExtensions, Verify, AccErr); + validate_extensions(OtpCert, Rest, NewValidationState, ExistBasicCon, + SelfSigned, UserState, VerifyFun); -validate_extensions([Extension | Rest], ValidationState, - ExistBasicCon, SelfSigned, UnknownExtensions, - Verify, AccErr) -> - validate_extensions(Rest, ValidationState, ExistBasicCon, SelfSigned, - [Extension | UnknownExtensions], Verify, AccErr). +validate_extensions(OtpCert, [#'Extension'{} = Extension | Rest], + ValidationState, ExistBasicCon, + SelfSigned, UserState0, VerifyFun) -> + UserState = verify_fun(OtpCert, {extension, Extension}, UserState0, VerifyFun), + validate_extensions(OtpCert, Rest, ValidationState, ExistBasicCon, SelfSigned, + UserState, VerifyFun). is_valid_key_usage(KeyUse, Use) -> lists:member(Use, KeyUse). diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl index f9b992afd3..68bf04eeff 100644 --- a/lib/public_key/src/public_key.erl +++ b/lib/public_key/src/public_key.erl @@ -109,7 +109,8 @@ pem_entry_decode({Asn1Type, CryptDer, {Cipher, Salt}} = PemEntry, %%-------------------------------------------------------------------- -spec pem_entry_encode(pki_asn1_type(), term()) -> pem_entry(). -spec pem_entry_encode(pki_asn1_type(), term(), - {{Cipher :: string(), Salt :: binary()}, string()}) -> pem_entry(). + {{Cipher :: string(), Salt :: binary()}, string()}) -> + pem_entry(). % %% Description: Creates a pem entry that can be feed to pem_encode/1. %%-------------------------------------------------------------------- @@ -440,17 +441,25 @@ pkix_normalize_name(Issuer) -> CertChain :: [der_encoded()] , Options :: list()) -> {ok, {PublicKeyInfo :: term(), - PolicyTree :: term(), - [{bad_cert, Reason :: term()}]}} | + PolicyTree :: term()}} | {error, {bad_cert, Reason :: term()}}. %% Description: Performs a basic path validation according to RFC 5280. %%-------------------------------------------------------------------- -pkix_path_validation(unknown_ca, [Cert | Chain], Options) -> - case proplists:get_value(verify, Options, true) of - true -> - {error, {bad_cert, unknown_ca}}; - false -> - pkix_path_validation(Cert, Chain, [{acc_errors, [{bad_cert, unknown_ca}]}]) +pkix_path_validation(unknown_ca, [Cert | Chain], Options0) -> + {VerifyFun, Userstat0} = + proplists:get_value(verify_fun, Options0, ?DEFAULT_VERIFYFUN), + Otpcert = pkix_decode_cert(Cert, otp), + Reason = {bad_cert, unknown_ca}, + try VerifyFun(Otpcert, Reason, Userstat0) of + {valid, Userstate} -> + Options = proplists:delete(verify_fun, Options0), + pkix_path_validation(Otpcert, Chain, [{verify_fun, + {VerifyFun, Userstate}}| Options]); + {fail, _} -> + {error, Reason} + catch + _:_ -> + {error, Reason} end; pkix_path_validation(TrustedCert, CertChain, Options) when is_binary(TrustedCert) -> OtpCert = pkix_decode_cert(TrustedCert, @@ -462,12 +471,7 @@ pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options) ValidationState = pubkey_cert:init_validation_state(TrustedCert, MaxPathDefault, Options), - Fun = proplists:get_value(validate_extensions_fun, Options, - fun(Extensions, State, _, AccError) -> - {Extensions, State, AccError} - end), - Verify = proplists:get_value(verify, Options, true), - path_validation(CertChain, ValidationState, Fun, Verify). + path_validation(CertChain, ValidationState). %%-------------------------------------------------------------------- %%% Internal functions @@ -490,38 +494,40 @@ path_validation([], #path_validation_state{working_public_key_algorithm PublicKey, working_public_key_parameters = PublicKeyParams, - valid_policy_tree = Tree, - acc_errors = AccErrors - }, _, _) -> - {ok, {{Algorithm, PublicKey, PublicKeyParams}, Tree, AccErrors}}; + valid_policy_tree = Tree + }) -> + {ok, {{Algorithm, PublicKey, PublicKeyParams}, Tree}}; path_validation([DerCert | Rest], ValidationState = #path_validation_state{ - max_path_length = Len}, - Fun, Verify) when Len >= 0 -> - try validate(DerCert, - ValidationState#path_validation_state{last_cert=Rest=:=[]}, - Fun, Verify) of + max_path_length = Len}) when Len >= 0 -> + try validate(DerCert, + ValidationState#path_validation_state{last_cert=Rest=:=[]}) of #path_validation_state{} = NewValidationState -> - path_validation(Rest, NewValidationState, Fun, Verify) + path_validation(Rest, NewValidationState) catch throw:Reason -> {error, Reason} end; -path_validation(_, _, _, true) -> - {error, {bad_cert, max_path_length_reached}}; +path_validation([DerCert | _] = Path, + #path_validation_state{user_state = UserState0, + verify_fun = VerifyFun} = + ValidationState) -> + Reason = {bad_cert, max_path_length_reached}, + OtpCert = pkix_decode_cert(DerCert, otp), + try VerifyFun(OtpCert, Reason, UserState0) of + {valid, UserState} -> + path_validation(Path, + ValidationState#path_validation_state{ + max_path_length = 0, + user_state = UserState}); + {fail, _} -> + {error, Reason} + catch + _:_ -> + {error, Reason} + end. -path_validation(_, #path_validation_state{working_public_key_algorithm - = Algorithm, - working_public_key = - PublicKey, - working_public_key_parameters - = PublicKeyParams, - valid_policy_tree = Tree, - acc_errors = AccErrors - }, _, false) -> - {ok, {{Algorithm, PublicKey, PublicKeyParams}, Tree, - [{bad_cert, max_path_length_reached}|AccErrors]}}. validate(DerCert, #path_validation_state{working_issuer_name = Issuer, working_public_key = Key, @@ -531,40 +537,29 @@ validate(DerCert, #path_validation_state{working_issuer_name = Issuer, excluded_subtrees = Exclude, last_cert = Last, user_state = UserState0, - acc_errors = AccErr0} = - ValidationState0, ValidateExtensionFun, Verify) -> + verify_fun = VerifyFun} = + ValidationState0) -> OtpCert = pkix_decode_cert(DerCert, otp), - %% All validate functions will throw {bad_cert, Reason} if they - %% fail and Verify = true if Verify = false errors - %% will be accumulated in the validationstate - AccErr1 = pubkey_cert:validate_time(OtpCert, AccErr0, Verify), - AccErr2 = pubkey_cert:validate_issuer(OtpCert, Issuer, AccErr1, Verify), + UserState1 = pubkey_cert:validate_time(OtpCert, UserState0, VerifyFun), + + UserState2 = pubkey_cert:validate_issuer(OtpCert, Issuer, UserState1, VerifyFun), - AccErr3 = pubkey_cert:validate_names(OtpCert, Permit, Exclude, Last, - AccErr2, Verify), - AccErr4 = - pubkey_cert:validate_revoked_status(OtpCert, Verify, AccErr3), + UserState3 = pubkey_cert:validate_names(OtpCert, Permit, Exclude, Last, + UserState2,VerifyFun), + + UserState4 = pubkey_cert:validate_revoked_status(OtpCert, UserState3, VerifyFun), - {ValidationState1, UnknownExtensions0, AccErr5} = - pubkey_cert:validate_extensions(OtpCert, ValidationState0, Verify, - AccErr4), - %% We want the key_usage extension to be checked before we validate + {ValidationState1, UserState5} = + pubkey_cert:validate_extensions(OtpCert, ValidationState0, UserState4, + VerifyFun), + + %% We want the key_usage extension to be checked before we validate %% the signature. - AccErr6 = - pubkey_cert:validate_signature(OtpCert, DerCert, Key, KeyParams, - AccErr5, Verify), - - {UnknownExtensions, UserState, AccErr7} = - ValidateExtensionFun(UnknownExtensions0, UserState0, Verify, AccErr6), - - %% Check that all critical extensions have been handled - AccErr = - pubkey_cert:validate_unknown_extensions(UnknownExtensions, AccErr7, - Verify), + UserState = pubkey_cert:validate_signature(OtpCert, DerCert, + Key, KeyParams, UserState5, VerifyFun), ValidationState = - ValidationState1#path_validation_state{user_state = UserState, - acc_errors = AccErr}, + ValidationState1#path_validation_state{user_state = UserState}, pubkey_cert:prepare_for_next_cert(OtpCert, ValidationState). sized_binary(Binary) when is_binary(Binary) -> diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index 09235ff460..46b8c3db8b 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -369,16 +369,35 @@ pkix_path_validation(Config) when is_list(Config) -> CertK3 = {Cert3,_} = erl_make_certs:make_cert([{issuer, CertK1}, {extensions, [{basic_constraints, false}]}]), {Cert4,_} = erl_make_certs:make_cert([{issuer, CertK3}]), - {error, E={bad_cert,missing_basic_constraint}} = + {error, {bad_cert,missing_basic_constraint}} = public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4], []), - - {ok, {_,_,[E]}} = public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4], - [{verify,false}]), - - {error, {bad_cert,unknown_ca}} = public_key:pkix_path_validation(unknown_ca, [Cert1, Cert3, Cert4], []), - {ok, {_,_,[{bad_cert,unknown_ca}]}} = - public_key:pkix_path_validation(unknown_ca, [Cert1], [{verify, false}]), + VerifyFunAndState0 = {fun(_,{bad_cert, missing_basic_constraint}, UserState) -> + {valid, UserState}; + (_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState} + end, []}, + {ok, _} = + public_key:pkix_path_validation(Trusted, [Cert1, Cert3,Cert4], + [{verify_fun, VerifyFunAndState0}]), + + {error, {bad_cert, unknown_ca}} = + public_key:pkix_path_validation(unknown_ca, [Cert1, Cert3, Cert4], []), + + VerifyFunAndState1 = + {fun(_,{bad_cert, unknown_ca}, UserState) -> + {valid, UserState}; + (_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState} + end, []}, + + {ok, _} = + public_key:pkix_path_validation(unknown_ca, [Cert1], [{verify_fun, + VerifyFunAndState1}]), ok. %%-------------------------------------------------------------------- diff --git a/lib/reltool/test/Makefile b/lib/reltool/test/Makefile index 34781ae720..5109058797 100644 --- a/lib/reltool/test/Makefile +++ b/lib/reltool/test/Makefile @@ -74,7 +74,8 @@ release_spec: opt release_tests_spec: opt $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) reltool.spec $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR) - $(INSTALL_PROGRAM) rtt $(INSTALL_PROGS) $(RELSYSDIR) + $(INSTALL_SCRIPT) rtt $(INSTALL_PROGS) $(RELSYSDIR) + $(INSTALL_DATA) $(INSTALL_PROGS) $(RELSYSDIR) # chmod -f -R u+w $(RELSYSDIR) # @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) diff --git a/lib/runtime_tools/c_src/trace_file_drv.c b/lib/runtime_tools/c_src/trace_file_drv.c index 482fcc0288..cd54f36af0 100644 --- a/lib/runtime_tools/c_src/trace_file_drv.c +++ b/lib/runtime_tools/c_src/trace_file_drv.c @@ -520,7 +520,7 @@ static int do_write(FILETYPE fd, unsigned char *buff, int siz) { */ static int my_write(TraceFileData *data, unsigned char *buff, int siz) { - int wrote, w; + int wrote; if (data->buff_siz - data->buff_pos >= siz) { memcpy(data->buff + data->buff_pos, buff, siz); diff --git a/lib/runtime_tools/src/inviso_autostart.erl b/lib/runtime_tools/src/inviso_autostart.erl index 134133ad1f..787292e244 100644 --- a/lib/runtime_tools/src/inviso_autostart.erl +++ b/lib/runtime_tools/src/inviso_autostart.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. +%% Copyright Ericsson AB 2006-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -59,17 +59,10 @@ autostart(_AutoModArgs) -> case try_load_module(FileNames) of ok -> autostart_apply(M,F); + false -> % No such module available "inviso_autostart.config" end; - {ok,{gettia_asc,asc_file}} -> % Uggly hack to not have to change in GSN-CPS. - case try_load_module(["/tmp/DPE_COMMONLOG/gettia_asc", - "/tmp/DPE_COMMONLOG/gettia_overload"]) of - ok -> - autostart_apply(gettia_asc,asc_file); - false -> % No such module available - false - end; {ok,{M,F}} -> % Use M:F(node()) autostart_apply(M,F); {ok,no_autostart} -> diff --git a/lib/runtime_tools/src/inviso_autostart_server.erl b/lib/runtime_tools/src/inviso_autostart_server.erl index 5af96e4e39..1e352822f4 100644 --- a/lib/runtime_tools/src/inviso_autostart_server.erl +++ b/lib/runtime_tools/src/inviso_autostart_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. +%% Copyright Ericsson AB 2006-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -84,7 +84,7 @@ init(ArgsFromConfig) -> case get_tracerdata_opts(ArgsFromConfig) of {ok,TracerData} -> % Otherwise we can not start a trace! case inviso_rt:init_tracing(TracerData) of - {ok,_} -> % Ok, tracing has been initiated. + {ok,_Response} -> % Ok, tracing has been initiated. case get_cmdfiles_opts(ArgsFromConfig) of {ok,CmdFiles} -> % List of cmd-files. Bindings=get_initialbindings_opts(ArgsFromConfig), @@ -164,11 +164,11 @@ interpret_cmd_files([{FileName,LocalBindings}|Rest],GlobalBindings,Translations, Bindings=join_local_and_global_vars(LocalBindings,GlobalBindings), interpret_cmd_files_1(FileName,Bindings,Translations,Dbg), interpret_cmd_files(Rest,GlobalBindings,Translations,Dbg); -interpret_cmd_files([FileName|Rest],GlobalBindings,Translations,Dbg) -> - interpret_cmd_files_1(FileName,GlobalBindings,Translations,Dbg), - interpret_cmd_files(Rest,GlobalBindings,Translations,Dbg); interpret_cmd_files([],_,_,_) -> % Done, return nothing significant! - true. + true; +interpret_cmd_files(FileName,GlobalBindings,Translations,Dbg) -> + interpret_cmd_files_1(FileName,GlobalBindings,Translations,Dbg). +% interpret_cmd_files(Rest,GlobalBindings,Translations,Dbg). %% This is "inline" inviso calls. interpret_cmd_files_1({inviso,F,Args},Bindings,Translations,Dbg) -> diff --git a/lib/runtime_tools/test/Makefile b/lib/runtime_tools/test/Makefile new file mode 100644 index 0000000000..873d395277 --- /dev/null +++ b/lib/runtime_tools/test/Makefile @@ -0,0 +1,65 @@ +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +MODULES = \ + runtime_tools_SUITE \ + inviso_testmodule1_foo \ + inviso_SUITE \ + dbg_SUITE \ + erts_alloc_config_SUITE + +ERL_FILES= $(MODULES:%=%.erl) + +TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) +INSTALL_PROGS= $(TARGET_FILES) + +EMAKEFILE=Emakefile + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/runtime_tools_test + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- + +ERL_MAKE_FLAGS += +ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include + +EBIN = . + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +make_emakefile: + $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\ + > $(EMAKEFILE) + +tests debug opt: make_emakefile + erl $(ERL_MAKE_FLAGS) -make + +clean: + rm -f $(EMAKEFILE) + rm -f $(TARGET_FILES) + rm -f core + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + +release_tests_spec: make_emakefile + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) runtime_tools.spec $(ERL_FILES) $(RELSYSDIR) + $(INSTALL_DATA) $(EMAKEFILE) runtime_tools.cover $(RELSYSDIR) + chmod -f -R u+w $(RELSYSDIR) + @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) + +release_docs_spec: diff --git a/lib/runtime_tools/test/dbg_SUITE.erl b/lib/runtime_tools/test/dbg_SUITE.erl new file mode 100644 index 0000000000..ff96af5e86 --- /dev/null +++ b/lib/runtime_tools/test/dbg_SUITE.erl @@ -0,0 +1,901 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(dbg_SUITE). + +%% Test functions +-export([all/1, big/1, tiny/1, simple/1, message/1, distributed/1, + ip_port/1, file_port/1, file_port2/1, file_port_schedfix/1, + ip_port_busy/1, wrap_port/1, wrap_port_time/1, + with_seq_trace/1, dead_suspend/1, local_trace/1, + saved_patterns/1]). +-export([init_per_testcase/2, fin_per_testcase/2]). +-export([tracee1/1, tracee2/1]). +-export([dummy/0, exported/1]). + +-include("test_server.hrl"). +-define(default_timeout, ?t:minutes(1)). + +init_per_testcase(_Case, Config) -> + ?line Dog=test_server:timetrap(?default_timeout), + [{watchdog, Dog}|Config]. +fin_per_testcase(_Case, Config) -> + Dog=?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. + +all(suite) -> [big, tiny, simple, message, distributed, + ip_port, file_port, file_port2, file_port_schedfix, + ip_port_busy, wrap_port, wrap_port_time, + with_seq_trace, dead_suspend, local_trace, saved_patterns]. + +big(suite) -> []; +big(doc) -> ["Rudimentary interface test"]; +big(Config) when is_list(Config) -> + ?line {ok,OldCurDir} = file:get_cwd(), + Datadir=?config(data_dir, Config), + Privdir=?config(priv_dir, Config), + ?line ok=file:set_cwd(Privdir), + try + %% make sure dbg is stopped (and returns correctly) + ?line ok = dbg:stop(), + + %% compile test module and make sure it is loaded. + ?line {ok,Mod} = compile:file(Datadir++"/dbg_test",[trace]), + ?line code:purge(dbg_test), + ?line {module, Mod}=code:load_file(dbg_test), + + %% run/debug a named test function. + ?line Pid = spawn_link(dbg_test, loop, [Config]), + ?line true = register(dbg_test_loop, Pid), + ?line {ok,_} = dbg:tracer(), + ?line {ok,[{matched, _node, 1}]} = dbg:p(dbg_test_loop, [m,p,c]), + ?line ok = dbg:c(dbg_test, test, [Config]), + ?line ok = dbg:i(), + ?line dbg_test_loop ! {dbg_test, stop}, + unregister(dbg_test_loop), + ?line ok = dbg:stop(), + + %% run/debug a Pid. + ?line Pid2=spawn_link(dbg_test,loop,[Config]), + ?line {ok,_} = dbg:tracer(), + ?line {ok,[{matched, _node, 1}]} = dbg:p(Pid2,[s,r,p]), + ?line ok = dbg:c(dbg_test, test, [Config]), + ?line ok = dbg:i(), + ?line Pid2 ! {dbg_test, stop}, + + ?line ok=file:set_cwd(OldCurDir) + after + ?line dbg:stop() + end, + ok. + + +tiny(suite) -> []; +tiny(doc) -> ["Rudimentary interface test"]; +tiny(Config) when is_list(Config) -> + ?line {ok,OldCurDir} = file:get_cwd(), + Datadir=?config(data_dir, Config), + Privdir=?config(priv_dir, Config), + ?line ok=file:set_cwd(Privdir), + try + %% compile test module and make sure it is loaded. + ?line {ok, Mod} = compile:file(Datadir++"/dbg_test",[trace]), + ?line code:purge(dbg_test), + ?line {module, Mod}=code:load_file(dbg_test), + + ?line Pid=spawn_link(dbg_test,loop,[Config]), + if + is_pid(Pid) -> + ?line dbg:tracer(), + ?line {ok,[{matched, _node, 1}]} = dbg:p(Pid,[s,r,m,p,c]), + ?line ok = dbg:c(dbg_test,test,[Config]), + ?line ok = dbg:i(), + ?line Pid ! {dbg_test, stop}; + true -> + ?line ok=file:set_cwd(OldCurDir), + ?t:fail("Could not spawn external test process.~n"), + failure + end + after + ?line ok = dbg:stop(), + ?line ok = file:set_cwd(OldCurDir) + end, + ok. + +simple(suite) -> + []; +simple(doc) -> + ["Simple interface test with own handler"]; +simple(Config) when is_list(Config) -> + try + ?line start(), + ?line dbg:p(self(),call), + ?line dbg:tp(dbg,ltp,[]), + ?line dbg:ltp(), + ?line stop(), + ?line S = self(), + ?line [{trace,S,call,{dbg,ltp,[]}}] = flush() + after + ?line dbg:stop() + end, + ok. + +message(suite) -> + []; +message(doc) -> + ["Simple interface test with pam code that appends a message"]; +message(Config) when is_list(Config) -> + ?line {ok, _} = start(), + try + ?line {ok, [{matched, _node, 1}]} = dbg:p(self(),call), + ?line {ok, X} = dbg:tp(dbg,ltp,[{'_',[],[{message, {self}}]}]), + ?line {value, {saved, Saved}} = lists:keysearch(saved, 1, X), + ?line {ok, Y} = dbg:tp(dbg,ln,Saved), + ?line {value, {saved, Saved}} = lists:keysearch(saved, 1, Y), + ?line ok = dbg:ltp(), + ?line ok = dbg:ln() + after + ?line stop() + end, + ?line S = self(), + ?line [{trace,S,call,{dbg,ltp,[]},S}, + {trace,S,call,{dbg,ln,[]},S}] = flush(), + ok. + +distributed(suite) -> + []; +distributed(doc) -> + ["Simple test of distributed tracing"]; +distributed(Config) when is_list(Config) -> + ?line {ok, _} = start(), + ?line Node = start_slave(), + try + ?line RexPid = rpc:call(Node, erlang, whereis, [rex]), + ?line RexPidList = pid_to_list(RexPid), + ?line {ok, Node} = dbg:n(Node), + ?line {ok, X} = dbg:p(all,call), + ?line {value, {matched, Node, _}} = lists:keysearch(Node, 2, X), + ?line {ok, Y} = dbg:p(RexPidList, s), + ?line {value, {matched, Node, 1}} = lists:keysearch(Node, 2, Y), + ?line {ok, Z} = dbg:tp(dbg,ltp,[]), + ?line {value, {matched, Node, 1}} = lists:keysearch(Node, 2, Z), + ?line dbg:cn(Node), + ?line dbg:tp(dbg,ln,[]), + ?line ok = rpc:call(Node, dbg, ltp, []), + ?line ok = rpc:call(Node, dbg, ln, []), + ?line ok = dbg:ln(), + ?line S = self(), + ?line {TraceSend, TraceCall} = + lists:partition(fun ({trace,RP,send,_,_}) when RP =:= RexPid -> true; + (_) -> false end, + flush()), + ?line [_|_] = TraceSend, + ?line [{trace,Pid,call,{dbg,ltp,[]}}, + {trace,S,call,{dbg,ln,[]}}] = TraceCall, + ?line Node = node(Pid), + %% + ?line stop() + after + ?line stop_slave(Node), + ?line stop() + end, + ok. + + +local_trace(suite) -> + []; +local_trace(doc) -> + ["Tests tracing of local function calls."]; +local_trace(Config) when is_list(Config) -> + ?line {ok, _} = start(), + try + ?line S = self(), + ?line %% Split "<X.Y.Z>" into {X, Y, Z} + ?line "<"++L1 = L = pid_to_list(S), + ?line NoDot = fun ($.) -> false; (_) -> true end, + ?line {LX,"."++L2} = lists:splitwith(NoDot, L1), + ?line {LY,"."++L3} = lists:splitwith(NoDot, L2), + ?line ">"++L4 = lists:reverse(L3), + ?line LZ = lists:reverse(L4), + ?line X = 0 = list_to_integer(LX), + ?line Y = list_to_integer(LY), + ?line Z = list_to_integer(LZ), + ?line XYZ = {X, Y, Z}, + ?line io:format("Self = ~w = ~w~n", [S,XYZ]), + ?line {ok, [{matched, _node, 1}]} = dbg:p(S,call), + ?line {ok, [{matched, _node, 1}]} = dbg:p(XYZ,call), + if Z =:= 0 -> + ?line {ok, [{matched, _node, 1}]} = dbg:p(Y,call); + true -> ok + end, + ?line {ok, [{matched, _node, 1}]} = dbg:p(L,call), + ?line {ok, _} = dbg:tpl(?MODULE,not_exported,[]), + ?line 4 = not_exported(2), + ?line [{trace,S,call,{?MODULE,not_exported,[2]}}] = flush(), + ?line {ok, _} = dbg:tp(?MODULE,exported,[]), + ?line 4 = ?MODULE:exported(2), + ?line [{trace,S,call,{?MODULE,exported,[2]}}, + {trace,S,call,{?MODULE,not_exported,[2]}}] = flush(), + ?line {ok, _} = dbg:ctpl(?MODULE), + ?line 4 = ?MODULE:exported(2), + ?line [{trace,S,call,{?MODULE,exported,[2]}}] = flush(), + ?line {ok, _} = dbg:tpl(?MODULE,not_exported,[]), + ?line {ok, _} = dbg:ctp(?MODULE), + ?line 4 = ?MODULE:exported(2), + ?line [] = flush(), + ?line {ok, _} = dbg:tpl(?MODULE,not_exported,x), + ?line catch ?MODULE:exported(x), + ?line [{trace,S,call,{dbg_SUITE,not_exported,[x]}}, + {trace,S,exception_from, + {dbg_SUITE,not_exported,1}, + {error,badarith}}] = flush() + after + ?line stop() + end, + ok. + +saved_patterns(suite) -> + []; +saved_patterns(doc) -> + ["Tests saving of match_spec's."]; +saved_patterns(Config) when is_list(Config) -> + ?line dbg:stop(), + ?line {ok,[{saved,1}]} = + dbg:tp(dbg,ctp,1,[{'_',[],[{message, blahonga}]}]), + ?line {ok,[{saved,2}]} = + dbg:tp(dbg,ctp,1,[{['_'],[],[{message, blahonga}]}]), + ?line Privdir=?config(priv_dir, Config), + ?line file:make_dir(Privdir), + ?line File = filename:join([Privdir, "blahonga.ms"]), + ?line dbg:wtp(File), + ?line dbg:stop(), + ?line dbg:ctp('_','_','_'), + ?line {ok, _} = start(), + try + ?line dbg:rtp(File), + ?line {ok,[{matched,_node,1},{saved,1}]} = dbg:tp(dbg,ltp,0,1), + ?line {ok, [{matched, _node, 1}]} = dbg:p(self(),call), + ?line dbg:ltp(), + ?line S = self(), + ?line [{trace,S,call,{dbg,ltp,[]},blahonga}] = flush() + after + ?line stop() + end, + ok. + + + +not_exported(N) -> + N * 2. + +exported(N) -> + not_exported(N). + +ip_port(suite) -> + []; +ip_port(doc) -> + ["Test tracing to IP port"]; +ip_port(Config) when is_list(Config) -> + ?line stop(), + ?line Port = dbg:trace_port(ip, 0), + ?line {ok, _} = dbg:tracer(port, Port), + try + ?line {ok, [{matched, _node, 1}]} = dbg:p(self(),call), + ?line {ok, X} = dbg:tp(dbg, ltp,[{'_',[],[{message, {self}}]}]), + ?line {value, {saved, _Saved}} = lists:keysearch(saved, 1, X), + ?line {ok, Y} = dbg:tp(dbg, ln, [{'_',[],[{message, hej}]}]), + ?line {value, {saved, _}} = lists:keysearch(saved, 1, Y), + ?line ok = dbg:ltp(), + ?line ok = dbg:ln(), + ?line {ok, IpPort} = dbg:trace_port_control(get_listen_port), + ?line io:format("IpPort = ~p~n", [IpPort]), + ?line dbg:trace_client(ip, IpPort, {fun myhandler/2, self()}), + ?line S = self(), + ?line [{trace,S,call,{dbg,ltp,[]},S}, + {trace,S,call,{dbg,ln,[]},hej}] = flush() + after + ?line stop() + end, + ok. + + + +ip_port_busy(suite) -> + []; +ip_port_busy(doc) -> + ["Test that the dbg server does not hang if the tracer don't start ", + "(OTP-3592)"]; +ip_port_busy(Config) when is_list(Config) -> + ?line stop(), + ?line Tracer = dbg:trace_port(ip, 4745), + ?line Port = Tracer(), + ?line {error, Reason} = dbg:tracer(port, Tracer), + try + ?line io:format("Error reason = ~p~n", [Reason]), + ?line true = port_close(Port) + after + ?line dbg:stop() + end, + ?line ok. + + + +file_port(suite) -> + []; +file_port(doc) -> + ["Test tracing to file port (simple)"]; +file_port(Config) when is_list(Config) -> + ?line stop(), + ?line {A,B,C} = erlang:now(), + ?line FTMP = atom_to_list(?MODULE) ++ integer_to_list(A) ++ "-" ++ + integer_to_list(B) ++ "-" ++ integer_to_list(C), + ?line FName = filename:join([?config(data_dir, Config), FTMP]), + ?line Port = dbg:trace_port(file, FName), + ?line {ok, _} = dbg:tracer(port, Port), + try + ?line {ok, [{matched, _node, 1}]} = dbg:p(self(),call), + ?line {ok, X} = dbg:tp(dbg, ltp,[{'_',[],[{message, {self}}]}]), + ?line {value, {saved, _Saved}} = lists:keysearch(saved, 1, X), + ?line {ok, Y} = dbg:tp(dbg, ln, [{'_',[],[{message, hej}]}]), + ?line {value, {saved, _}} = lists:keysearch(saved, 1, Y), + ?line ok = dbg:ltp(), + ?line ok = dbg:ln(), + ?line stop(), + ?line dbg:trace_client(file, FName, {fun myhandler/2, self()}), + ?line S = self(), + ?line [{trace,S,call,{dbg,ltp,[]},S}, + {trace,S,call,{dbg,ln,[]},hej}, + end_of_trace] = flush() + after + ?line stop(), + ?line file:delete(FName) + end, + ok. + +file_port2(suite) -> + []; +file_port2(doc) -> + ["Test tracing to file port with 'follow_file'"]; +file_port2(Config) when is_list(Config) -> + case os:type() of + vxworks -> + {skipped, "VxWorks NFS cache ruins it all."}; + _ -> + ?line stop(), + ?line {A,B,C} = erlang:now(), + ?line FTMP = atom_to_list(?MODULE) ++ integer_to_list(A) ++ + "-" ++ integer_to_list(B) ++ "-" ++ integer_to_list(C), + ?line FName = filename:join([?config(data_dir, Config), FTMP]), + %% Ok, lets try with flush and follow_file, not a chance on VxWorks + %% with NFS caching... + ?line Port2 = dbg:trace_port(file, FName), + ?line {ok, _} = dbg:tracer(port, Port2), + try + ?line {ok, [{matched, _node, 1}]} = dbg:p(self(),call), + ?line {ok, _} = dbg:tp(dbg, ltp,[{'_',[],[{message, {self}}]}]), + ?line {ok, _} = dbg:tp(dbg, ln, [{'_',[],[{message, hej}]}]), + ?line ok = dbg:ltp(), + ?line ok = dbg:flush_trace_port(), + ?line dbg:trace_client(follow_file, FName, + {fun myhandler/2, self()}), + ?line S = self(), + ?line [{trace,S,call,{dbg,ltp,[]},S}] = flush(), + ?line ok = dbg:ln(), + ?line ok = dbg:flush_trace_port(), + ?line receive after 1000 -> ok end, %% Polls every second... + ?line [{trace,S,call,{dbg,ln,[]},hej}] = flush(), + ?line stop(), + ?line [] = flush() + after + ?line stop(), + ?line file:delete(FName) + end, + ok + end. + +file_port_schedfix(suite) -> + []; +file_port_schedfix(doc) -> + ["Test that the scheduling timestamp fix for trace flag 'running' works."]; +file_port_schedfix(Config) when is_list(Config) -> + ?line case (catch erlang:system_info(smp_support)) of + true -> + {skip, "No schedule fix on SMP"}; + _ -> + try + file_port_schedfix1(Config) + after + dbg:stop() + end + end. +file_port_schedfix1(Config) when is_list(Config) -> + ?line stop(), + ?line {A,B,C} = erlang:now(), + ?line FTMP = atom_to_list(?MODULE) ++ integer_to_list(A) ++ + "-" ++ integer_to_list(B) ++ "-" ++ integer_to_list(C), + ?line FName = filename:join([?config(data_dir, Config), FTMP]), + %% + ?line Port = dbg:trace_port(file, {FName, wrap, ".wraplog", 8*1024, 4}), + ?line {ok, _} = dbg:tracer(port, Port), + ?line {ok,[{matched,_node,0}]} = dbg:p(new,[running,procs,send,timestamp]), + %% + %% Generate the trace data + %% + %% This starts 3 processes that sends a message to each other in a ring, + %% 4 laps. Prior to sending the message to the next in the ring, each + %% process send 8 messages to itself, just to generate some trace data, + %% and to lower the possibility that the trace log wraps just after + %% a schedule out message (which would not burden any process and hence + %% not show up in the result) + %% + %% The wrap file trace is used because it burns a lot of time when the + %% driver swaps files, a lot more than the regular file trace. The test + %% case is dimensioned so that the log fills two files and just starts + %% on the third (out of four wrap files). This gives two file swaps, + %% and there are three processes, so one process will NOT be burdened. + %% The criterion for trace success is then that the max process + %% execution time must not be more than twice the min process + %% execution time. Wallclock. A normal result is about 10 times more + %% without schedule in - schedule out compensation (OTP-3938). + %% + ?line ok = token_volleyball(3, 4, 8), + %% + ?line {ok,[{matched,_,_}]} = dbg:p(all, [clear]), + ?line stop(), + % Some debug code to run on all platforms, for finding the fault on genny + % Dont touch please /PaN + ?line io:format("Trace dump by PaN BEGIN~n"), + ?line dbg:trace_client(file,{FName, wrap, ".wraplog"},{fun(end_of_trace,Pid)-> Pid ! done; (Mesg,Pid) -> io:format("~w~n",[Mesg]),Pid end,self()}), + receive done -> ok end, + ?line io:format("Trace dump by PaN END~n"), + %% + %% Get the trace result + %% + ?line Tag = make_ref(), + ?line dbg:trace_client(file, {FName, wrap, ".wraplog"}, + {fun schedstat_handler/2, {self(), Tag, []}}), + ?line Result = + receive + {Tag, D} -> + lists:map( + fun({Pid, {A1, B1, C1}}) -> + {Pid, C1/1000000 + B1 + A1*1000000} + end, + D) + end, + ?line ok = io:format("Result=~p", [Result]), +% erlang:display({?MODULE, ?LINE, Result}), + %% + %% Analyze the result + %% + ?line {Min, Max} = + lists:foldl( + fun({_Pid, M}, {Mi, Ma}) -> + {if M < Mi -> M; true -> Mi end, + if M > Ma -> M; true -> Ma end} + end, + {void, 0}, + Result), + % More PaN debug + ?line io:format("Min = ~f, Max = ~f~n",[Min,Max]), + %% + %% Cleanup + %% + ?line ToBeDeleted = filelib:wildcard(FName++"*"++".wraplog"), + ?line lists:map({file, delete}, ToBeDeleted), +% io:format("ToBeDeleted=~p", [ToBeDeleted]), + %% + %% Present the result + %% + P = (Max / Min - 1) * 100, + BottomLine = lists:flatten(io_lib:format("~.2f %", [P])), + if P > 100 -> + Reason = {BottomLine, '>', "100%"}, + erlang:display({file_port_schedfix, fail, Reason}), + test_server:fail(Reason); + true -> + {comment, BottomLine} + end. + +wrap_port(suite) -> + []; +wrap_port(doc) -> + ["Test tracing to wrapping file port"]; +wrap_port(Config) when is_list(Config) -> + ?line Self = self(), + ?line stop(), + ?line {A,B,C} = erlang:now(), + ?line FTMP = atom_to_list(?MODULE) ++ integer_to_list(A) ++ "-" ++ + integer_to_list(B) ++ "-" ++ integer_to_list(C) ++ "-", + ?line FName = filename:join([?config(data_dir, Config), FTMP]), + ?line FNameWildcard = FName++"*"++".trace", + %% WrapSize=0 and WrapCnt=11 will force the trace to wrap after + %% every trace message, and to contain only the last 10 entries + %% after trace stop since the last file will be empty waiting + %% for its first trace message. + ?line WrapSize = 0, + ?line WrapCnt = 11, + ?line WrapFilesSpec = {FName, wrap, ".trace", WrapSize, WrapCnt}, + ?line wrap_port_init(WrapFilesSpec), + %% The number of iterations, N, is tested to place wrap the log, + %% giving a gap in the filename sequence at index 3. + %% This should be a difficult case for + %% the trace_client file sorting functionality. + N = 7, + ?line lists:foreach( + fun(Cnt) -> + ?MODULE:tracee1(Cnt), + ?MODULE:tracee2(Cnt) + end, + lists:seq(1, N)), + ?line stop(), + try + ?line Files1 = filelib:wildcard(FNameWildcard), + ?line io:format("~p~n", [Files1]), + ?line Tc1 = dbg:trace_client(file, WrapFilesSpec, + {fun myhandler/2, {wait_for_go,Self}}), + ?line Tref1 = erlang:monitor(process, Tc1), + Tc1 ! {go,Self}, + ?line [{'DOWN',Tref1,_,_,normal}, + end_of_trace + |Result] = lists:reverse(flush()), + ?line M = N - (WrapCnt-1) div 2, + ?line M = wrap_port_result(Result, Self, N), + %% + %% Start a new wrap log with the same name to verify that + %% all files are cleared at wrap log start. Only produce + %% two trace messages to also place the gap at index 3, + %% so the trace log will be misinterpreted. + %% + ?line wrap_port_init(WrapFilesSpec), + ?line Files2 = filelib:wildcard(FNameWildcard), + ?line io:format("~p~n", [Files2]), + ?line -1 = ?MODULE:tracee1(-1), + ?line -1 = ?MODULE:tracee2(-1), + ?line stop(), + ?line Files = filelib:wildcard(FNameWildcard), + ?line io:format("~p~n", [Files]), + ?line Tc2 = dbg:trace_client(file, WrapFilesSpec, + {fun myhandler/2, {wait_for_go,Self}}), + ?line Tref2 = erlang:monitor(process, Tc2), + Tc2 ! {go,Self}, + ?line [{trace,Self,call,{?MODULE,tracee1,[-1]},Self}, + {trace,Self,call,{?MODULE,tracee2,[-1]},hej}, + end_of_trace, + {'DOWN',Tref2,_,_,normal}] = flush(), + %% + ?line lists:map(fun(F) -> file:delete(F) end, Files) + after + ?line stop() + end, + ok. + +wrap_port_init(WrapFilesSpec) -> + ?line Port = dbg:trace_port(file, WrapFilesSpec), + ?line {ok, _} = dbg:tracer(port, Port), + ?line {ok, [{matched, _node, 1}]} = dbg:p(self(),call), + ?line {ok, X} = dbg:tp(?MODULE, tracee1,[{'_',[],[{message, {self}}]}]), + ?line {value, {saved, _Saved}} = lists:keysearch(saved, 1, X), + ?line {ok, Y} = dbg:tp(?MODULE, tracee2, [{'_',[],[{message, hej}]}]), + ?line {value, {saved, _}} = lists:keysearch(saved, 1, Y), + ok. + +tracee1(X) -> + X. + +tracee2(X) -> + X. + +wrap_port_result([], _S, M) -> + M; +wrap_port_result([{trace, S, call, {?MODULE, tracee2, [M]}, hej}, + {trace, S, call, {?MODULE, tracee1, [M]}, S} | Tail], + S, + M) -> + wrap_port_result(Tail, S, M-1). + + +wrap_port_time(suite) -> + []; +wrap_port_time(doc) -> + ["Test tracing to time limited wrapping file port"]; +wrap_port_time(Config) when is_list(Config) -> + ?line stop(), + ?line {A,B,C} = erlang:now(), + ?line FTMP = atom_to_list(?MODULE) ++ integer_to_list(A) ++ "-" ++ + integer_to_list(B) ++ "-" ++ integer_to_list(C) ++ "-", + ?line FName = filename:join([?config(data_dir, Config), FTMP]), + %% WrapTime=2 and WrapCnt=4 will force the trace to wrap after + %% every 2 seconds, and to contain between 3*2 and 4*2 seconds + %% of trace entries. + ?line WrapFilesSpec = {FName, wrap, ".trace", {time, 2000}, 4}, + ?line Port = dbg:trace_port(file, WrapFilesSpec), + ?line {ok, _} = dbg:tracer(port, Port), + try + ?line {ok, [{matched, _node, 1}]} = dbg:p(self(),call), + ?line {ok, X} = dbg:tp(?MODULE, tracee1,[{'_',[],[{message, {self}}]}]), + ?line {value, {saved, _Saved1}} = lists:keysearch(saved, 1, X), + ?line {ok, Y} = dbg:tp(?MODULE, tracee2, [{'_',[],[{message, hej}]}]), + ?line {value, {saved, _Saved2}} = lists:keysearch(saved, 1, Y), + %% The delays in the iterations places two trace messages in each + %% trace file, but the last which is empty waiting for its first + %% trace message. The number of iterations is chosen so that + %% one trace file has been wasted, and therefore the first pair + %% of trace messages. + ?line lists:foreach( + fun(Cnt) -> + receive after 1000 -> ok end, + ?MODULE:tracee1(Cnt), + ?MODULE:tracee2(Cnt), + receive after 1100 -> ok end + end, + lists:seq(1, 4)), + ?line stop(), + ?line Files = filelib:wildcard(FName ++ "*" ++ ".trace"), + ?line io:format("~p~n", [Files]), + ?line dbg:trace_client(file, WrapFilesSpec, {fun myhandler/2, self()}), + ?line S = self(), + ?line [{trace, S, call, {?MODULE, tracee1, [2]}, S}, + {trace, S, call, {?MODULE, tracee2, [2]}, hej}, + {trace, S, call, {?MODULE, tracee1, [3]}, S}, + {trace, S, call, {?MODULE, tracee2, [3]}, hej}, + {trace, S, call, {?MODULE, tracee1, [4]}, S}, + {trace, S, call, {?MODULE, tracee2, [4]}, hej}, + end_of_trace] = flush(), + ?line lists:map(fun(F) -> file:delete(F) end, Files) + after + ?line stop() + end, + ok. + +with_seq_trace(suite) -> + []; +with_seq_trace(doc) -> + ["Test ordinary tracing combined with seq_trace"]; +with_seq_trace(Config) when is_list(Config) -> + try + ?line {ok, Server} = start(), + ?line {ok, Tracer} = dbg:get_tracer(), + ?line {ok, X} = dbg:tp(dbg, get_tracer, [{[],[], + [{set_seq_token, send, true}]}]), + ?line {value, {saved, _}} = lists:keysearch(saved, 1, X), + ?line {ok, [{matched, _node, 1}]} = dbg:p(self(),call), + ?line seq_trace:set_system_tracer(Tracer), + ?line dbg:get_tracer(), + receive + after 1 -> + ok + end, + ?line S = self(), + ?line ThisNode = node(), + ?line [{trace,S,call,{dbg,get_tracer,[]}}, + {seq_trace,0,{send,_,S,Server,{S,{get_tracer,ThisNode}}}}, + {seq_trace,0,{send,_,Server,S,{dbg,{ok,Tracer}}}}] = + flush() + after + ?line stop() + end, + ok. + +dead_suspend(suite) -> + []; +dead_suspend(doc) -> + ["Test that trace messages concerning a now dead process does " + "not crash dbg."]; + +dead_suspend(Config) when is_list(Config) -> + ?line start(), + try + survived = run_dead_suspend() + after + ?line stop() + end. + +run_dead_suspend() -> + dbg:p(new, call), + dbg:tp(?MODULE, dummy, []), + spawn(?MODULE, dummy, []), + spawn(?MODULE, dummy, []), + spawn(?MODULE, dummy, []), + spawn(?MODULE, dummy, []), + spawn(?MODULE, dummy, []), + receive after 1000 -> ok end, + case whereis(dbg) of + undefined -> + died; + _ -> + survived + end. + +dummy() -> + ok. + + +%% +%% Support functions +%% + +start_slave() -> + {A, B, C} = now(), + Name = "asdkxlkmd" ++ integer_to_list(A+B+C), + {ok, Node} = test_server:start_node(Name,slave,[]), + ok = wait_node(Node, 15), + Node. + +stop_slave(Node) -> + test_server:stop_node(Node). + +wait_node(_,0) -> + no; +wait_node(Node, N) -> + case net_adm:ping(Node) of + pong -> + ok; + pang -> + receive + after 1000 -> + ok + end, + wait_node(Node, N - 1) + end. + +myhandler(Message, {wait_for_go,Pid}) -> + receive + {go,Pid} -> + myhandler(Message, Pid) + end; +myhandler(Message, Relay) -> + Relay ! Message, + case Message of + end_of_trace -> + ok; + _ -> + Relay + end. + +flush() -> + flush([]). +flush(Acc) -> + receive + X -> + flush(Acc ++ [X]) + after 1000 -> + Acc + end. + +start() -> + stop(), + dbg:tracer(process, {fun myhandler/2, self()}). + +stop() -> + dbg:stop(). + + + +schedstat_handler(TraceMsg, {Parent, Tag, Data} = State) -> + case TraceMsg of + {trace_ts, Pid, in, _, Ts} -> + NewData = + case lists:keysearch(Pid, 1, Data) of + {value, {Pid, Acc}} -> + [{Pid, Acc, Ts} | lists:keydelete(Pid, 1, Data)]; + false -> + [{Pid, {0, 0, 0}, Ts} | Data]; + Other -> + exit(Parent, {?MODULE, ?LINE, Other}), + erlang:display({?MODULE, ?LINE, Other}), + Data + end, + {Parent, Tag, NewData}; + {trace_ts, Pid, out, _, {A3, B3, C3}} -> + NewData = + case lists:keysearch(Pid, 1, Data) of + {value, {Pid, {A1, B1, C1}, {A2, B2, C2}}} -> + [{Pid, {A3-A2+A1, B3-B2+B1, C3-C2+C1}} | + lists:keydelete(Pid, 1, Data)]; + Other -> + exit(Parent, {?MODULE, ?LINE, Other}), + erlang:display({?MODULE, ?LINE, Other}), + Data + end, + {Parent, Tag, NewData}; + {trace_ts, Pid, exit, normal, {A3, B3, C3}} -> + NewData = + case lists:keysearch(Pid, 1, Data) of + {value, {Pid, {A1, B1, C1}, {A2, B2, C2}}} -> + [{Pid, {A3-A2+A1, B3-B2+B1, C3-C2+C1}} | + lists:keydelete(Pid, 1, Data)]; + {value, {Pid, _Acc}} -> + Data; + false -> + [{Pid, {0, 0, 0}} | Data]; + Other -> + exit(Parent, {?MODULE, ?LINE, Other}), + erlang:display({?MODULE, ?LINE, Other}), + Data + end, + {Parent, Tag, NewData}; + {trace_ts, _Pid, send, _Msg, _OtherPid, _Ts} -> + State; + end_of_trace -> + Parent ! {Tag, Data}, + State + end. + + + +pass_token(Token, Next, Loops) -> + receive + {Token, 1} = Msg -> + sendloop(Loops), + Next ! Msg; + {Token, _Cnt} = Msg-> + sendloop(Loops), + Next ! Msg, + pass_token(Token, Next, Loops) + end. + +pass_token(Token, Final, Cnt, Loops) -> + receive + {Token, start, Next} -> + sendloop(Loops), + Msg = {Token, Cnt}, + Next ! Msg, + pass_token(Token, Final, Next, Cnt, Loops) + end. + +pass_token(Token, Final, Next, Cnt, Loops) -> + receive + {Token, 1} -> + sendloop(Loops), + Msg = {Token, done}, + Final ! Msg; + {Token, Cnt} -> + sendloop(Loops), + NextCnt = Cnt-1, + Msg = {Token, NextCnt}, + Next ! Msg, + pass_token(Token, Final, Next, NextCnt, Loops) + end. + +sendloop(Loops) -> + sendloop(make_ref(), Loops). + +sendloop(_Tag, 0) -> + ok; +sendloop(Tag, Loops) -> + self() ! {Tag, Loops}, + receive {Tag, Loops} -> ok end, + sendloop(Tag, Loops-1). + +token_volleyball(N, Cnt, Loops) + when is_integer(N), N >= 1, is_integer(Cnt), Cnt >= 1, + is_integer(Loops), Loops >= 0 -> + Self = self(), + Token = make_ref(), + Last = spawn_link(fun() -> pass_token(Token, Self, Cnt, Loops) end), + First = token_volleyball(Token, Last, N-1, Loops), + Last ! {Token, start, First}, + receive {Token, done} -> ok end. + +token_volleyball(Token, Next, 1, Loops) -> + spawn_link(fun() -> pass_token(Token, Next, Loops) end); +token_volleyball(Token, Next, N, Loops) -> + Pid = spawn_link(fun() -> pass_token(Token, Next, Loops) end), + token_volleyball(Token, Pid, N-1, Loops). diff --git a/lib/runtime_tools/test/dbg_SUITE_data/dbg_test.erl b/lib/runtime_tools/test/dbg_SUITE_data/dbg_test.erl new file mode 100644 index 0000000000..2edbf6f99a --- /dev/null +++ b/lib/runtime_tools/test/dbg_SUITE_data/dbg_test.erl @@ -0,0 +1,87 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%%%---------------------------------------------------------------------- +%%% Purpose : A priority queue. +%%%---------------------------------------------------------------------- +%%% This module implements a priority queue as defined in +%%% "Priority Queues and the STL" by Mark Nelson in Dr.Dobb's Journal, Jan 1996 +%%% see http://web2.airmail.net/markn/articles/pq_stl/priority.htm for more +%%% information. (A heap implementation is planned aswell) +%%%---------------------------------------------------------------------- +%%% The items of the queue is kept priority sorted, and because of that, +%%% a push() operation costs more than a pop() operation (wich only +%%% needs to return the top item of the queue(read: list)). +%%%---------------------------------------------------------------------- +%%% The priority queue can be deceptively nice to use when creating for +%%% example a Huffman coding tree. +%%% See http://web2.airmail.net/markn/articles/pq_stl/priority.htm or +%%% Dr.Dobb's Journal Jan, 96 for more information on this. +%%%---------------------------------------------------------------------- + +%%% Used here strictly as something for dbg_SUITE to run. + +-module(dbg_test). +-export([test/1, loop/1]). +-export([new/0, push/3, pop/1]). + +loop(Config) -> + test(Config), + receive + {dbg_test, stop} -> + ok; + Other -> + loop(Config) + end, + ok. + +test(Config) -> + Q1=new(), + Q2=push(Q1, "monkey", 3), + Q3=push(Q2, "banana", 4), + Q4=push(Q3, "jungle", 2), + Q5=push(Q4, "world", 5), + Q6=push(Q5, "universe",6), + Q7=push(Q6, "peanut", 1), +% io:format("~p~n",[Q7]), + {Itm, Q8}=pop(Q7), + ok. + +%% Returns a new priority queue. +new() -> + []. + +%% Pushes a new item with a set priority into the queue. +push(Queue, Itm, Pri) -> + insert(Queue, Itm, Pri, []). + +%% Pops the item with the highest priority out of the queue. +pop([{Itm, Pri}|Queue]) -> + {Itm, Queue}. + +%% --- -- - +%% Support functions. +insert([], Itm, Pri, NewQ) -> + lists:flatten([lists:reverse(NewQ)|[{Itm, Pri}]]); +% Itm>QItm>NewQ>Queue +insert([{QItm,QPri}|Queue], Itm, Pri, NewQ) when Pri>QPri-> + A = [{Itm, Pri}|[{QItm, QPri}]], + lists:flatten([[A|NewQ]|Queue]); +insert([QItm|Rest], Itm, Pri, NewQ) -> + insert(Rest, Itm, Pri, [QItm|NewQ]). +%% --- -- - diff --git a/lib/runtime_tools/test/dbg_SUITE_data/exref_td.erl b/lib/runtime_tools/test/dbg_SUITE_data/exref_td.erl new file mode 100644 index 0000000000..85faf620aa --- /dev/null +++ b/lib/runtime_tools/test/dbg_SUITE_data/exref_td.erl @@ -0,0 +1,50 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(exref_td). + +-export([a/1,b/1,c/1,d/1,e/1,my_analyse/1]). + +a("edcba") -> + true; +a(_) -> + lists:reverse("abcde"). + +b(_) -> + a(nil). + +c(_) -> + nonexistentmodule:f(). + +d(_) -> + lists:nonexistentfunction(). + +e(_) -> + [a(x),b(x),c(x)]. + +localfuncnotcalled() -> + true. + +localfunccalledbyf(A) -> + A. + +f() -> + lists:filter(fun localfunccalledbyf/1,"aaabba"), + F = fun localfuncnotcalled/0. + +my_analyse(Graph) -> ok. diff --git a/lib/runtime_tools/test/erts_alloc_config_SUITE.erl b/lib/runtime_tools/test/erts_alloc_config_SUITE.erl new file mode 100644 index 0000000000..32483dbe73 --- /dev/null +++ b/lib/runtime_tools/test/erts_alloc_config_SUITE.erl @@ -0,0 +1,206 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(erts_alloc_config_SUITE). + +%-define(line_trace, 1). + +-include("test_server.hrl"). + +%-compile(export_all). +-export([all/1, init_per_testcase/2, fin_per_testcase/2]). + +%% Testcases +-export([basic/1]). + +%% internal export +-export([make_basic_config/1]). + +-define(DEFAULT_TIMEOUT, ?t:minutes(2)). + +all(doc) -> []; +all(suite) -> [basic]. + +init_per_testcase(Case, Config) when is_list(Config) -> + [{testcase, Case}, + {watchdog, ?t:timetrap(?DEFAULT_TIMEOUT)}, + {erl_flags_env, save_env()} | Config]. + +fin_per_testcase(_Case, Config) when is_list(Config) -> + ?t:timetrap_cancel(?config(watchdog, Config)), + restore_env(?config(erl_flags_env, Config)), + ok. + +%%% +%%% The test cases ------------------------------------------------------------ +%%% + +basic(doc) -> []; +basic(suite) -> []; +basic(Config) when is_list(Config) -> + ?line ErtsAllocConfig = privfile("generated", Config), + + SbctMod = " +MBsbct 1024 +MHsbct 4096", + + %% Make sure we have enabled allocators + ZFlgs = case os:getenv("ERL_ZFLAGS") of + FlgString when is_list(FlgString) -> + FlgString; + _ -> + "" + end ++ " +Mea max +Mea config", + + ?line os:putenv("ERL_ZFLAGS", ZFlgs ++ SbctMod), + + ?line {ok, Node1} = start_node(Config), + ?line ok = rpc:call(Node1, ?MODULE, make_basic_config, [ErtsAllocConfig]), + ?line stop_node(Node1), + + ?line display_file(ErtsAllocConfig), + + ?line ManualConfig = privfile("manual", Config), + ?line {ok, IOD} = file:open(ManualConfig, [write]), + ?line io:format(IOD, "~s", ["+MBsbct 2048"]), + ?line file:close(IOD), + ?line display_file(ManualConfig), + + ?line os:putenv("ERL_ZFLAGS", ZFlgs), + + ?line {ok, Node2} = start_node(Config, + "-args_file " ++ ErtsAllocConfig + ++ " -args_file " ++ ManualConfig), + + ?line {_, _, _, Cfg} = rpc:call(Node2, erlang, system_info, [allocator]), + + ?line stop_node(Node2), + + ?line {value,{binary_alloc, BCfg}} = lists:keysearch(binary_alloc, 1, Cfg), + ?line {value,{sbct, 2097152}} = lists:keysearch(sbct, 1, BCfg), + ?line {value,{eheap_alloc, HCfg}} = lists:keysearch(eheap_alloc, 1, Cfg), + ?line {value,{sbct, 4194304}} = lists:keysearch(sbct, 1, HCfg), + + ?line ok. + +make_basic_config(ErtsAllocConfig) -> + %% Save some different scenarios + Tester = self(), + SSBegun = make_ref(), + SSDone = make_ref(), + SSFun = fun (F) -> + receive + SSDone -> + ok = erts_alloc_config:save_scenario(), + Tester ! SSDone + after 500 -> + ok = erts_alloc_config:save_scenario(), + F(F) + end + end, + SS = spawn_link(fun () -> + ok = erts_alloc_config:save_scenario(), + Tester ! SSBegun, + SSFun(SSFun) + end), + receive SSBegun -> ok end, + Ref = make_ref(), + Tab = ets:new(?MODULE, [bag, public]), + Ps = lists:map( + fun (_) -> + spawn_link( + fun () -> + ets:insert(Tab, + {self(), + lists:seq(1, 1000)}), + receive after 1000 -> ok end, + Tester ! {Ref, self()} + end) + end, + lists:seq(1, 10000)), + lists:foreach(fun (P) -> receive {Ref, P} -> ok end end, Ps), + ets:delete(Tab), + SS ! SSDone, + receive SSDone -> ok end, + + ok = erts_alloc_config:make_config(ErtsAllocConfig). + + + +%% +%% Utils ---------------------------------------------------------------------- +%% + +display_file(FileName) -> + ?t:format("filename: ~s~n", [FileName]), + {ok, Bin} = file:read_file(FileName), + io:format("~s", [binary_to_list(Bin)]), + ?t:format("eof: ~s~n", [FileName]), + ok. + +mk_name(Config) when is_list(Config) -> + {A, B, C} = now(), + list_to_atom(atom_to_list(?MODULE) + ++ "-" ++ atom_to_list(?config(testcase, Config)) + ++ "-" ++ integer_to_list(A) + ++ "-" ++ integer_to_list(B) + ++ "-" ++ integer_to_list(C)). + +start_node(Config) -> + start_node(Config, ""). + +start_node(Config, Args) -> + ?line Pa = filename:dirname(code:which(?MODULE)), + ?line ?t:start_node(mk_name(Config), + slave, + [{args, "-pa " ++ Pa ++ " " ++ Args}]). + +stop_node(Node) -> + ?line true = ?t:stop_node(Node). + +privfile(Name, Config) -> + filename:join([?config(priv_dir, Config), + atom_to_list(?config(testcase, Config)) ++ "." ++ Name]). + +save_env() -> + {erl_flags, + os:getenv("ERL_AFLAGS"), + os:getenv("ERL_FLAGS"), + os:getenv("ERL_"++erlang:system_info(otp_release)++"_FLAGS"), + os:getenv("ERL_ZFLAGS")}. + +restore_env(EVar, false) when is_list(EVar) -> + restore_env(EVar, ""); +restore_env(EVar, "") when is_list(EVar) -> + case os:getenv(EVar) of + false -> ok; + "" -> ok; + " " -> ok; + _ -> os:putenv(EVar, " ") + end; +restore_env(EVar, Value) when is_list(EVar), is_list(Value) -> + case os:getenv(EVar) of + Value -> ok; + _ -> os:putenv(EVar, Value) + end. + +restore_env({erl_flags, AFlgs, Flgs, RFlgs, ZFlgs}) -> + restore_env("ERL_AFLAGS", AFlgs), + restore_env("ERL_FLAGS", Flgs), + restore_env("ERL_"++erlang:system_info(otp_release)++"_FLAGS", RFlgs), + restore_env("ERL_ZFLAGS", ZFlgs), + ok. diff --git a/lib/runtime_tools/test/inviso_SUITE.erl b/lib/runtime_tools/test/inviso_SUITE.erl new file mode 100644 index 0000000000..1c5c887b62 --- /dev/null +++ b/lib/runtime_tools/test/inviso_SUITE.erl @@ -0,0 +1,2840 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% Description: +%% Test suite for inviso (basic parts, i.e not inviso tools). Note that +%% inviso basic parts have modules in both the runtime_tools and +%% inviso applications. +%% +%% Authors: +%% Ann-Marie L�f, ann-marie.lof@st.se +%% Lennart �hman, lennart.ohman@st.se +%% ----------------------------------------------------------------------------- + +-module(inviso_SUITE). +-compile(export_all). + +-include("test_server.hrl"). +-include_lib("kernel/include/file.hrl"). + +-define(l,?line). + +all(suite) -> + [ + basic_dist_trace_1, + basic_dist_trace_2, + basic_dist_trace_3, + basic_dist_trace_ti_1, + basic_dist_trace_ti_2, + basic_dist_trace_ti_3, + suspend_dist_trace_ti_1, + suspend_dist_trace_ti_2, + meta_cleanfunc_dist_1, + basic_handlerfun_dist_1, + delete_log_dist_1, + autostart_dist_1, + autostart_dist_2, + autostart_dist_3, + running_alone_dist_1, + running_alone_dist_2, + running_alone_dist_3, + running_alone_dist_4, + running_alone_dist_5, + overload_dist_1, + overload_dist_2, + overload_dist_3, + overload_dist_4, + overload_dist_5, + subscribe_dist_1, + lfm_trace_dist_1, + lfm_trace_ti_dist_2, + handle_logfile_sort_wrapset, + fetch_log_dist_trace_1, + fetch_log_dist_trace_2, + fetch_log_dist_trace_3, + fetch_log_dist_error_1, + fetch_log_dist_error_2, + expand_regexp_dist_1, + only_loaded_dist_1 + ]. + + +init_per_suite(Config) -> + %% No never know who skrewed up this node before this suite! :-) + erlang:trace_pattern({'_','_','_'},[],[local]), + erlang:trace_pattern({'_','_','_'},[],[global]), + erlang:trace(all,false,[all]), + + ?l ok=application:start(runtime_tools), + Config. + +end_per_suite(_Config) -> + ?l ok=application:stop(runtime_tools). + + +%% For each distributed testcase, we need two other distributed nodes to run the +%% runtime components on. Since they are freshly started every time there is no +%% need to clean them up first. +init_per_testcase(_Case,Config) -> + ?l TH=test_server:timetrap(100000), + ?l {ok,Node1}=test_server:start_node(inviso1,peer,[]), + ?l {ok,Node2}=test_server:start_node(inviso2,peer,[]), + ?l SuiteDir=filename:dirname(code:which(?MODULE)), + + %% Otherwise peer nodes will not find this module! + ?l true=rpc:call(Node1,code,add_patha,[SuiteDir]), + ?l true=rpc:call(Node2,code,add_patha,[SuiteDir]), + + ?l start_side_effect_logger(node()), + ?l start_side_effect_logger(Node1), + ?l start_side_effect_logger(Node2), + + + %% SPECIAL FOR MY PRIVATE TEST ENVIROMENT +% ?l rpc:call(Node1,code,add_patha,["/clearcase/otp/tools/runtime_tools/ebin"]), +% ?l rpc:call(Node1,code,add_patha,["/clearcase/otp/tools/inviso/ebin"]), +% ?l rpc:call(Node2,code,add_patha,["/clearcase/otp/tools/runtime_tools/ebin"]), +% ?l rpc:call(Node2,code,add_patha,["/clearcase/otp/tools/inviso/ebin"]), + +% %% SPECIAL FOR MY PRIVATE TEST ENVIROMENT, windows. +% ?l rpc:call(Node1,code,add_patha,["Z:/DATA/PROJECTS/inviso_project/runtime_tools/ebin"]), +% ?l rpc:call(Node1,code,add_patha,["Z:/DATA/PROJECTS/inviso_project/inviso/ebin"]), +% ?l rpc:call(Node2,code,add_patha,["Z:/DATA/PROJECTS/inviso_project/runtime_tools/ebin"]), +% ?l rpc:call(Node2,code,add_patha,["Z:/DATA/PROJECTS/inviso_project/inviso/ebin"]), + + ?l ok=rpc:call(Node1,application,start,[runtime_tools]), + ?l ok=rpc:call(Node2,application,start,[runtime_tools]), + ?l timer:sleep(100), % Problem with autostarted runtime. + %% The following is a test that the inviso_rt processes which are autostarted + %% are now gone. + + ?l ok=poll(rpc,call,[Node1,erlang,whereis,[inviso_rt]],undefined,20), + ?l ok=poll(rpc,call,[Node2,erlang,whereis,[inviso_rt]],undefined,20), + +% ?l ok=poll(rpc,call,[Node1,supervisor,which_children,[runtime_tools_sup]],[],20), +% ?l ok=poll(rpc,call,[Node2,supervisor,which_children,[runtime_tools_sup]],[],20), + NewConfig1=insert_remotenode_config(inviso1,Node1,Config), + NewConfig2=insert_remotenode_config(inviso2,Node2,NewConfig1), + insert_timetraphandle_config(TH,NewConfig2). +%% ----------------------------------------------------------------------------- + +fin_per_testcase(Case,Config) -> + ?l test_server:stop_node(get_remotenode_config(inviso1,Config)), + ?l test_server:stop_node(get_remotenode_config(inviso2,Config)), + + case whereis(inviso_c) of + undefined -> % Should not exist. + true; + Pid when is_pid(Pid) -> % But if it exists... + exit(Pid,kill), % Remove it! + io:format("Had to kill the control component in fin_per_testcase,~p.~n",[Case]) + end, + case whereis(inviso_rt) of + undefined -> % Should not exist. + true; + Pid2 when is_pid(Pid2) -> % But if it exists... + exit(Pid2,kill), % Remove it! + io:format("Had to kill local runtime component in fin_per_testcase,~p.~n",[Case]) + end, + ?l process_killer([inviso_test_proc, + inviso_tab_proc, + inviso_collector_proc, + global_inviso_test_proc]), + ?l test_server:timetrap_cancel(get_timetraphandle_config(Config)), + + NewConfig1=remove_remotenode_config(inviso1,Config), + NewConfig2=remove_remotenode_config(inviso2,NewConfig1), + remove_timetraphandle_config(NewConfig2). +%% ----------------------------------------------------------------------------- + +%% ============================================================================== +%% Testcases. +%% ============================================================================== + +%% TEST CASE: Basic, distributed, trace only. +basic_dist_trace_1(suite) -> []; +basic_dist_trace_1(doc) -> + ["Basic case, start of distributed tracing, using only trac."]; +basic_dist_trace_1(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList=lists:map(fun(N)->{N,{file,filename:join([PrivDir, + "tf1_"++ + atom_to_list(N) + ])}} end, + Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), + activate_local_tracing(Nodes), + deactivate_local_tracing(Nodes), + stop_tracing(Nodes), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + + +%% TEST CASE: Basic, distributed, activate global tracing for functions in modules +%% pointed out using a regexp. No tracing will be done. +basic_dist_trace_2(suite) -> []; +basic_dist_trace_2(doc) -> + [""]; +basic_dist_trace_2(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList=lists:map(fun(N)->{N,{file,filename:join([PrivDir, + "tf1a_"++ + atom_to_list(N) + ])}} end, + Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), + Funcs1=activate_global_tracing_regexp(Nodes), + deactivate_global_tracing_regexp(Nodes,Funcs1), + stop_tracing(Nodes), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Basic, distributed, activate global tracing for functions in modules +%% pointed out using a dir-regexp. No tracing will be done. +basic_dist_trace_3(suite) -> []; +basic_dist_trace_3(doc) -> + [""]; +basic_dist_trace_3(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList=lists:map(fun(N)->{N,{file,filename:join([PrivDir, + "tf1b_"++ + atom_to_list(N) + ])}} end, + Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), + Funcs1=activate_global_tracing_regexp_dir(Nodes), + deactivate_global_tracing_regexp_dir(Nodes,Funcs1), + stop_tracing(Nodes), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Basic, distributed, trace and ti. +basic_dist_trace_ti_1(suite) -> []; +basic_dist_trace_ti_1(doc) -> + [""]; +basic_dist_trace_ti_1(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataFun= + fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf2_"++atom_to_list(N)])}}, + {ti,{file,filename:join([PrivDir,"tf2_"++atom_to_list(N)++".ti"])}}]} + end, + TracerDataList=lists:map(TracerDataFun,Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), + activate_local_tracing(Nodes), + activate_meta_tracing(Nodes), + ?l true=(is_pid(whereis(inviso_rt))), + ?l true=(is_pid(whereis(inviso_rt_meta))), + deactivate_meta_tracing(Nodes), + deactivate_local_tracing(Nodes), + stop_tracing(Nodes), + ?l true=(is_pid(whereis(inviso_rt))), % Shall still be running. + ?l ok=poll(erlang,whereis,[inviso_rt_meta],undefined,3), + stop(Nodes), + timer:sleep(200), % Give it time to terminate. + ?l ok=poll(erlang,whereis,[inviso_rt],undefined,3),% Shall be gone now. + ?l undefined=whereis(inviso_rt_meta), % Still gone. + ok. +%% ----------------------------------------------------------------------------- + +%% Test CASE: Testing that the tpm_tracer functionality works. That is appending +%% {tracer,Tracer} to a meta match spec. +basic_dist_trace_ti_2(suite) -> []; +basic_dist_trace_ti_2(doc) -> + [""]; +basic_dist_trace_ti_2(Config) when is_list(Config) -> + case erlang:system_info(version) of + "5.4"++_ -> % Perhaps not perfect, but work now :-) + {skip,"Old emulator"}; + _ -> + basic_dist_trace_ti_2_do(Config) + end. + +basic_dist_trace_ti_2_do(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataFun= + fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf3_"++atom_to_list(N)])}}, + {ti,{file,filename:join([PrivDir,"tf3_"++atom_to_list(N)++".ti"])}}]} + end, + TracerDataList=lists:map(TracerDataFun,Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), + activate_deactivate_meta_tracing_tracer(Nodes), + stop_tracing(Nodes), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Basic, distributed, trace and ti, where we try to use ctp_all to +%% check that all global and local patterns are removed but that meta patterns +%% remain. +%% This test also checks that if the meta tracer is terminated an error value +%% is generated when trying to do meta tracing at that node. +basic_dist_trace_ti_3(suite) -> []; +basic_dist_trace_ti_3(doc) -> + [""]; +basic_dist_trace_ti_3(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataFun= + fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf4_"++atom_to_list(N)])}}, + {ti,{file,filename:join([PrivDir,"tf4_"++atom_to_list(N)++".ti"])}}]} + end, + TracerDataList=lists:map(TracerDataFun,Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), + activate_local_tracing(Nodes), + activate_global_tracing(Nodes), + activate_meta_tracing(Nodes), + ?l true=(is_pid(whereis(inviso_rt))), + ?l true=(is_pid(whereis(inviso_rt_meta))), + ?l {ok,NodeResults1}=inviso:ctp_all(Nodes), % Removes local and global patterns. + ?l true=check_noderesults(Nodes,ok,NodeResults1), + ?l true=check_on_nodes(Nodes,erlang,trace_info,[{code,which,1},traced],{traced,false}), + ?l true=check_on_nodes(Nodes,erlang,trace_info,[{code,get_path,0},traced],{traced,false}), + %% But meta patters shall remain. + ?l true=check_on_nodes(Nodes, + erlang, + trace_info, + [{lists,module_info,0},meta_match_spec], + fun({meta_match_spec,L})when length(L)>0 ->true end), + ?l true=check_on_nodes(Nodes, + erlang, + trace_info, + [{lists,module_info,0},meta], + fun({meta,P})when is_pid(P) -> + P=rpc:call(node(P),erlang,whereis,[inviso_rt_meta]), + true + end), + %% Now kill the meta tracer somewhere and try to activate meta tracing. + ?l [ANode|_]=Nodes, + ?l AMetaPid=rpc:call(ANode,erlang,whereis,[inviso_rt_meta]), + ?l rpc:call(ANode,erlang,exit,[AMetaPid,kill]), + ?l {ok,NodeResults2}=inviso:tpm(Nodes,math,pi,0,[],void), + ?l {value,{ANode,{error,_}}}=lists:keysearch(ANode,1,NodeResults2), + + ?l stop_tracing(Nodes), + ?l stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% ----------------------------------------------------------------------------- +%% Test cases for SUSPEND +%% ----------------------------------------------------------------------------- + +%% TEST CASE: In this test case a trace with ti is started. Trace flags are set, +%% trace patterns are set and meta trace patterns. We then check that the trace +%% flags and the meta patterns are removed when tracing suspended. +%% The suspension is cancelled and we check that it is possible to reactivate +%% tracing by setting the process flags and meta patterns again. +suspend_dist_trace_ti_1(suite) -> []; +suspend_dist_trace_ti_1(doc) -> + [""]; +suspend_dist_trace_ti_1(Config) when is_list(Config) -> + ?l RemoteNodes=get_remotenodes_config(Config), + ?l Nodes=[node()|RemoteNodes], + ?l PrivDir=filename:join(?config(priv_dir,Config),""), + ?l TracerDataFun= + fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf_suspend1_"++atom_to_list(N)])}}, + {ti,{file,filename:join([PrivDir,"tf_suspend1_"++atom_to_list(N)++".ti"])}}]} + end, + ?l TracerDataList=lists:map(TracerDataFun,Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), + activate_local_tracing(Nodes), + activate_meta_tracing(Nodes), + ?l true=(is_pid(whereis(inviso_rt))), + ?l true=(is_pid(whereis(inviso_rt_meta))), + %% Set some trace flags on some newly started test procs. + activate_traceflags(Nodes), + + %% Now suspend the tracing on all nodes. That shall result in the removal + %% of trace flags and meta trace patterns, but not local trace patterns. + ?l {ok,NodeResults1}=inviso:suspend(Nodes,test), + ?l true=check_noderesults(Nodes,ok,NodeResults1), + %% Trace flags gone? + ?l TestProcs=lists:map(fun(N)->rpc:call(N,erlang,whereis,[inviso_test_proc]) end,Nodes), + ?l lists:foreach(fun(P)-> + {flags,[]}= + rpc:call(node(P),erlang,trace_info,[P,flags]) + end, + TestProcs), + %% Meta patterns shall be gone too, but local functions still there. + ?l lists:foreach(fun(N)-> + {meta,false}= + rpc:call(N, + erlang, + trace_info, + [{math,module_info,1},meta]), + {traced,local}= + rpc:call(N, + erlang, + trace_info, + [{code,which,1},traced]) + end, + Nodes), + + %% Try to activate trace flags, trace patterns and meta tracing while + %% suspended. Should not succeed of course! + ?l ThisNode=node(), + ?l {ok,[{ThisNode,{error,suspended}}]}= + inviso:tf([ThisNode],inviso_test_proc,[call]), + ?l {ok,[{ThisNode,{error,suspended}}]}= + inviso:tpl([ThisNode],math,module_info,1,[]), + ?l {ok,[{ThisNode,{error,suspended}}]}= + inviso:init_tpm([ThisNode], + math, + module_info, + 1, + {?MODULE,tpm_init_func2}, % Does not exist on purpose. + {?MODULE,tpm_call_func2}, % Does not exist on purpose. + {?MODULE,tpm_return_func2}, % Does not exist on purpose. + {?MODULE,tpm_remove_func2}), % Does not exist on purpose. + + %% Now we want to cancel suspension and see that we can reactivate tracing. + ?l {ok,NodeResults2}=inviso:cancel_suspension(Nodes), + ?l true=check_noderesults(Nodes,ok,NodeResults2), + + ?l {ok,NodeResults3}= + inviso:init_tpm(math, + module_info, + 1, + {?MODULE,tpm_init_func2}, % Does not exist on purpose. + {?MODULE,tpm_call_func2}, % Does not exist on purpose. + {?MODULE,tpm_return_func2}, % Does not exist on purpose. + {?MODULE,tpm_remove_func2}), % Does not exist on purpose. + ?l true=check_noderesults(Nodes,ok,NodeResults3), + ?l {ok,NodeResults5}= + inviso:tpm_ms(math,module_info,1,ms1,[{'_',[],[{return_trace}]}]), + ?l true=check_noderesults(Nodes,{ok,1},NodeResults5), + ?l true=check_on_nodes(Nodes, + erlang, + trace_info, + [{math,module_info,1},meta_match_spec], + {meta_match_spec,[{'_',[],[{return_trace}]}]}), + ?l {ok,NodeResults6}=inviso:tf(Nodes,inviso_test_proc,[call]), + ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults6), + + %deactivate_meta_tracing(Nodes), + %deactivate_local_tracing(Nodes), + stop_tracing(Nodes), + ?l true=(is_pid(whereis(inviso_rt))), % Shall still be running. + ?l ok=poll(erlang,whereis,[inviso_rt_meta],undefined,3), + stop(Nodes), + ?l timer:sleep(200), % Give it time to terminate. + ?l ok=poll(erlang,whereis,[inviso_rt],undefined,3),% Shall be gone now. + ?l undefined=whereis(inviso_rt_meta), % Still gone. + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: In this test case a trace with ti is started. Trace flags are set, +%% trace patterns are set and meta trace patterns. We then suspend tracing at +%% all nodes, then stop tracing which shall be allowed. We then try to initiate +%% tracing again which shall not be possible. +suspend_dist_trace_ti_2(suite) -> []; +suspend_dist_trace_ti_2(doc) -> + [""]; +suspend_dist_trace_ti_2(Config) when is_list(Config) -> + ?l RemoteNodes=get_remotenodes_config(Config), + ?l Nodes=[node()|RemoteNodes], + ?l PrivDir=filename:join(?config(priv_dir,Config),""), + ?l TracerDataFun= + fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf_suspend2_"++atom_to_list(N)])}}, + {ti,{file,filename:join([PrivDir,"tf_suspend2_"++atom_to_list(N)++".ti"])}}]} + end, + ?l TracerDataList=lists:map(TracerDataFun,Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), + activate_local_tracing(Nodes), + activate_meta_tracing(Nodes), + ?l true=(is_pid(whereis(inviso_rt))), + ?l true=(is_pid(whereis(inviso_rt_meta))), + %% Set some trace flags on some newly started test procs. + activate_traceflags(Nodes), + + %% Now suspend the tracing on all nodes. That shall result in the removal + %% of trace flags and meta trace patterns, but not local trace patterns. + ?l {ok,NodeResults1}=inviso:suspend(Nodes,test), + ?l true=check_noderesults(Nodes,ok,NodeResults1), + + %% Now stop tracing. + ?l {ok,NodeResults3}=inviso:stop_tracing(Nodes), + ?l true=check_noderesults(Nodes,{ok,idle},NodeResults3), + %% Now try to initiate tracing again. + ThisNode=node(), + ?l {ok,[{ThisNode,{error,suspended}}]}= + inviso:init_tracing([ThisNode], + [{trace,{file,filename:join([PrivDir,"tf_suspend3_"++ + atom_to_list(ThisNode)])}}, + {ti,{file,{filename:join([PrivDir,"tf_suspend3_"++ + atom_to_list(ThisNode)])}}}]), + + %% Cancel the suspension and initiate tracing again. + ?l {ok,NodeResults2}=inviso:cancel_suspension(Nodes), + ?l true=check_noderesults(Nodes,ok,NodeResults2), + ?l TracerDataFun2= + fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf_suspend4_"++atom_to_list(N)])}}, + {ti,{file,filename:join([PrivDir,"tf_suspend4_"++atom_to_list(N)++".ti"])}}]} + end, + ?l TracerDataList2=lists:map(TracerDataFun2,Nodes), + ?l {ok,NodeResults4}=inviso:init_tracing(TracerDataList2), + ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok},{ti_log,ok}]},NodeResults4), + stop_tracing(Nodes), + ?l true=(is_pid(whereis(inviso_rt))), % Shall still be running. + stop(Nodes), + ?l timer:sleep(200), % Give it time to terminate. + ?l ok=poll(erlang,whereis,[inviso_rt],undefined,3),% Shall be gone now. + ok. +%% ----------------------------------------------------------------------------- + + + +%% TEST CASE: This test case tests that the clean function removes (prosumed) +%% expired data from the internal public-loopdata structure in the inviso_rt_meta +%% process. +meta_cleanfunc_dist_1(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataFun= + fun(N)->{N,[{trace,{file,filename:join([PrivDir,"mcf1_"++atom_to_list(N)])}}, + {ti,{file,filename:join([PrivDir,"mcf1_"++atom_to_list(N)++".ti"])}}]} + end, + TracerDataList=lists:map(TracerDataFun,Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), + %% Now initialize meta tracing, but the call_func is a bit "fixed". + ?l {ok,NodeResults1}= + inviso:tpm(Nodes,math,module_info,1,[], + {?MODULE,meta_cleanfunc_initfunc_1}, + {?MODULE,meta_cleanfunc_callfunc_1}, + void,void), + ?l true=check_noderesults(Nodes,{ok,1},NodeResults1), + %% Nothing in the "our" part of the public loop data. + ?l true=check_on_nodes(Nodes, + inviso_rt_meta,get_state,[inviso_rt_meta], + fun({ok,_LD,{{_,[]},_}})->true end), + ?l lists:foreach(fun(N)->rpc:call(N,math,module_info,[exports]) end,Nodes), + %% Check that it has been added to the public loopdata structure. + ?l true=check_on_nodes(Nodes, + ?MODULE,poll,[inviso_rt_meta, + get_state, + [inviso_rt_meta], + fun({ok,_LD,{{_,[{meta_cleanfunc_test1,_Now}]},_}})-> + true; + (_)->false + end, + 20], + ok), + %% While we wait for 60 seconds to pass, we test a few other things. + ?l {ok,NodeResults2}= + inviso:tpm(Nodes,?MODULE,slowfunction2,0,[{'_',[],[{return_trace}]}], + {?MODULE,meta_cleanfunc_initfunc_2}, + {?MODULE,meta_cleanfunc_callfunc_2}, + {?MODULE,meta_cleanfunc_returnfunc_2}, + void), + ?l true=check_noderesults(Nodes,{ok,1},NodeResults2), + ?l lists:foreach(fun(N)->rpc:call(N,?MODULE,slowfunction,[]) end,Nodes), + %% Believe it or not but slowfunction is still running, in its own process, + %% we are therefore free now to examine the meta tracer. + ?l true=check_on_nodes(Nodes, + ?MODULE,poll,[inviso_rt_meta, + get_state, + [inviso_rt_meta], + fun({ok,_LD,{{[],Tuples},_}})-> + {value,_}= + lists:keysearch(meta_cleanfunc_test2, + 1, + Tuples), + {value,_}= + lists:keysearch(meta_cleanfunc_test1, + 1, + Tuples), + true; + (_)-> + false + end, + 20], + ok), + %% Now we wait for slowfunction to return and that the meta_cleanfunc_test2 + %% to be removed from public loopdata strucuture. + ?l timer:sleep(10000), + %% The only thing remaining should be the meta_cleanfunc_test1 which will not + %% go away for less than that the clean functionality removes it. + ?l true=check_on_nodes(Nodes, + ?MODULE,poll,[inviso_rt_meta, + get_state, + [inviso_rt_meta], + fun({ok,_LD,{{_,[{meta_cleanfunc_test1,_Now}]},_}})-> + true; + (_)-> + false + end, + 20], + ok), + %% Wait for the clean function to clean meta_cleanfunc_test1 away. + ?l timer:sleep(51000), % Shall be gone after 5 seconds. + ?l true=check_on_nodes(Nodes, + ?MODULE,poll,[inviso_rt_meta, + get_state, + [inviso_rt_meta], + fun({ok,_LD,{{_,[]},_}})->true; + (_)->false + end, + 20], + ok), + stop_tracing(Nodes), + stop(Nodes), + ok. + +%% This function acts as tpm initialization function when we are going to test +%% that the clean function works. Note that we here assume standard public loop +%% datastructure. +meta_cleanfunc_initfunc_1(_M,_F,_Arity,{E1,_E2}) -> + {ok,{E1,[]},void}. +%% Function that is supposed to be called when the meta traced function is +%% called. +meta_cleanfunc_callfunc_1(_Pid,_Args,{{E1,E2},Global}) -> + {ok,{{E1,[{meta_cleanfunc_test1,now()}|E2]},Global},void}. + +meta_cleanfunc_initfunc_2(_M,_F,_Arity,PublLD) -> + {ok,PublLD,void}. +meta_cleanfunc_callfunc_2(_Pid,_Args,{{E1,E2},Global}) -> + {ok,{{E1,[{meta_cleanfunc_test2,now()}|E2]},Global},void}. +meta_cleanfunc_returnfunc_2(_Pid,_,{{E1,E2},Global}) -> + {value,_}=lists:keysearch(meta_cleanfunc_test2,1,E2), + {ok,{{E1,lists:keydelete(meta_cleanfunc_test2,1,E2)},Global},void}. + +slowfunction() -> + spawn(?MODULE,slowfunction1,[]). +slowfunction1() -> + slowfunction2(). % Meta trace on this function call. +slowfunction2() -> + timer:sleep(2000), + true. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Testing that a runtime component can be started instructing it +%% to use a handler fun. Checks that the handler fun is called if a trace +%% message comes in. +basic_handlerfun_dist_1(suite) -> []; +basic_handlerfun_dist_1(doc) -> + [""]; +basic_handlerfun_dist_1(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + ?l lists:foreach(fun(N)->rpc:call(N,ets,insert,[inviso_sideeffect_tab,{bhf1,0}]) end, + Nodes), + TracerDataFun= + fun(N)->{N,{fun basic_handlerfun_dist_1_fun/2,inviso_sideeffect_tab}} end, + TracerDataList=lists:map(TracerDataFun,Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), + activate_local_tracing(Nodes), + activate_traceflags(Nodes), + ?l lists:foreach(fun(N)->[{bhf1,0}]= + rpc:call(N,ets,lookup,[inviso_sideeffect_tab,bhf1]) + end, + Nodes), + ?l inviso_test_proc ! {apply,code,which,[lists]}, + ok=poll(ets,lookup,[inviso_sideeffect_tab,bhf1],[{bhf1,1}],20), + deactivate_traceflags(Nodes), + deactivate_local_tracing(Nodes), + stop_tracing(Nodes), + timer:sleep(100), + ?l [{bhf1,1}]=ets:lookup(inviso_sideeffect_tab,bhf1), + stop(Nodes), + ok. + +%% Function used as handler fun for testcase above. +basic_handlerfun_dist_1_fun(_Msg,TId) -> + ets:update_counter(TId,bhf1,1), + TId. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Here we test that delete_log removes the files at the involved +%% runtime nodes. In this case we test that we remove logs according to last +%% used tracer data. +delete_log_dist_1(suite) -> []; +delete_log_dist_1(doc) -> [""]; +delete_log_dist_1(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataFun= + fun(N)->{N,[{trace,{file,filename:join([PrivDir,"dl1_"++atom_to_list(N)])}}, + {ti,{file,filename:join([PrivDir,"dl1_"++atom_to_list(N)++".ti"])}}]} + end, + TracerDataList=lists:map(TracerDataFun,Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), + ?l Files=lists:map(fun({N,TD})-> + ?l {value,{_,{_,TraceFile}}}=lists:keysearch(trace,1,TD), + ?l {value,{_,{_,TiFile}}}=lists:keysearch(ti,1,TD), + ?l {N,{TraceFile,TiFile}} + end, + TracerDataList), + io:format("The Files is:~w~n",[Files]), + ?l {ok,NodeResults1}=inviso:delete_log(Nodes), % Should not work! + ?l true=check_noderesults(Nodes,{error,tracing},NodeResults1), + stop_tracing(Nodes), + %% Files still here. + ?l lists:foreach(fun({N,{F1,F2}})-> + ?l {ok,_}=rpc:call(N,file,read_file_info,[F1]), + ?l {ok,_}=rpc:call(N,file,read_file_info,[F2]) + end, + Files), + ?l {ok,NodeResults2}=inviso:delete_log(Nodes), + ?l true=check_noderesults(Nodes, + fun({_N,{ok,LogInfos}})-> + ?l {value,{_,[{ok,_FName1}]}}= + lists:keysearch(trace_log,1,LogInfos), + ?l {value,{_,[{ok,_FName2}]}}= + lists:keysearch(ti_log,1,LogInfos), + true + end, + NodeResults2), + %% The files shall be gone now. + ?l lists:foreach(fun({N,{F1,F2}})-> + ?l {error,enoent}=rpc:call(N,file,read_file_info,[F1]), + ?l {error,enoent}=rpc:call(N,file,read_file_info,[F2]) + end, + Files), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + + +%% TEST CASE: Test of the autostart behaviour of the runtime component. +%% Here we test that a runtime component is started according to the autostart.conf +%% file. Note that the repeat parameter is set to 2. +autostart_dist_1(suite) -> []; +autostart_dist_1(doc) -> + [""]; +autostart_dist_1(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + PrivDir=filename:join(?config(priv_dir,Config),""), + AutoConfFile=filename:join(PrivDir,"autostart1.conf"), + [RNode|_]=RemoteNodes, + ?l ok=rpc:call(RNode,application,stop,[runtime_tools]), + ?l ok=rpc:call(RNode,application,set_env,[runtime_tools, + inviso_autostart_conf, + AutoConfFile]), + ?l {ok,FD}=file:open(AutoConfFile,[write]), + ?l ok=io:format(FD,"~w.~n~w.~n",[{repeat,2},{tag,c_ref}]), + ?l file:close(FD), + ?l ok=rpc:call(RNode,application,start,[runtime_tools]), + timer:sleep(1000), + ?l P1=rpc:call(RNode,erlang,whereis,[inviso_rt]), + ?l true=is_pid(P1), + ?l rpc:call(RNode,erlang,exit,[P1,kill]), + ?l ok=rpc:call(RNode,application,stop,[runtime_tools]), + ?l ok=rpc:call(RNode,application,start,[runtime_tools]), + timer:sleep(1000), + ?l P2=rpc:call(RNode,erlang,whereis,[inviso_rt]), + ?l true=is_pid(P2), + ?l rpc:call(RNode,erlang,exit,[P2,kill]), + ?l ok=rpc:call(RNode,application,stop,[runtime_tools]), + ?l ok=rpc:call(RNode,application,start,[runtime_tools]), + timer:sleep(1000), + ?l undefined=rpc:call(RNode,erlang,whereis,[inviso_rt]), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Test of autostart. Here we focus on that an autostarted +%% runtime component actually follows the trace case command file and +%% initiates tracing. +autostart_dist_2(suite) -> []; +autostart_dist_2(doc) -> + [""]; +autostart_dist_2(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + PrivDir=filename:join(?config(priv_dir,Config),""), + AutoConfFile=filename:join(PrivDir,"autostart2.conf"), + [RNode|_]=RemoteNodes, + ?l ok=rpc:call(RNode,application,stop,[runtime_tools]), + ?l ok=rpc:call(RNode,application,set_env,[runtime_tools, + inviso_autostart_conf, + AutoConfFile]), + ?l CmdFileName=filename:join(PrivDir,"autostart_cmd_as1"), + ?l {ok,FD}=file:open(CmdFileName,[write]), + ?l ok=io:format(FD, + "inviso:tpl(Nodes,M,F,Arity,[]).~n" + "inviso:tf(Nodes,inviso_test_proc,[call]).~n", + []), + ?l file:close(FD), + ?l TraceFileName=filename:join([PrivDir,"as1_"++atom_to_list(RNode)]), + ?l TiFileName=filename:join([PrivDir,"as1_"++atom_to_list(RNode)++".ti"]), + ?l inviso_as_lib:setup_autostart(RNode, + 2, + [], + [{trace,{file,TraceFileName}}, + {ti,{file,TiFileName}}], + [[CmdFileName]], + [{'M',code},{'F',which},{'Arity',1}], + [{{inviso,tpl,5},{inviso_rt,tpl,{erlang,tl}}}, + {{inviso,tf,3},{inviso_rt,tf,{erlang,tl}}}]), + ?l TestP=spawn(RNode,?MODULE,test_proc_init,[]), + ?l ok=rpc:call(RNode,application,start,[runtime_tools]), + ?l timer:sleep(1000), + ?l {ok,_}=file:read_file_info(TraceFileName), + ?l {ok,_}=file:read_file_info(TiFileName), + ?l true=is_pid(P=rpc:call(RNode,erlang,whereis,[inviso_rt])), + ?l ok=poll(rpc,call,[RNode,erlang,trace_info,[{code,which,1},traced]],{traced,local},10), + ?l {flags,[call]}=rpc:call(RNode,erlang,trace_info,[TestP,flags]), + ?l rpc:call(RNode,erlang,exit,[P,kill]), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Here we test that an autostarted runtime component with a dependency +%% to a specific control component tries to connect to that control component +%% during its start-up. +autostart_dist_3(suite) -> []; +autostart_dist_3(doc) -> + [""]; +autostart_dist_3(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + PrivDir=filename:join(?config(priv_dir,Config),""), + AutoConfFile=filename:join(PrivDir,"autostart3.conf"), + [RNode|_]=RemoteNodes, + ?l ok=rpc:call(RNode,application,stop,[runtime_tools]), + ?l ok=rpc:call(RNode,application,set_env,[runtime_tools, + inviso_autostart_conf, + AutoConfFile]), + ?l {ok,FD}=file:open(AutoConfFile,[write]), + ?l ok=io:format(FD,"~w.~n~w.~n~w.~n", + [{options,[{dependency,{infinity,node()}}]},{repeat,2},{tag,c_ref}]), + ?l file:close(FD), + %% Now start inviso at this node here for the runtime to connect. + ?l {ok,_Pid}=inviso:start(), + ?l ok=poll(erlang,whereis,[inviso_c],fun(P) when is_pid(P)->true;(_)->false end,10), + %% Make the runtime component start. + ?l ok=rpc:call(RNode,application,start,[runtime_tools]), + ?l ok=poll(rpc,call,[RNode,erlang,whereis,[inviso_rt]], + fun(P) when is_pid(P)->true;(_)->false end,10), + %% Check that the runtime component started. + ?l ok=poll(inviso,get_status,[[RNode]],{ok,[{RNode,{ok,{new,running}}}]},20), +% ?l {ok,[{RNode,{ok,{new,running}}}]}=inviso:get_status([RNode]), + stop([RNode]), + ok. +%% ----------------------------------------------------------------------------- + + + +%% TEST CASE: Test of the dependency mechanism in the runtime component. +%% Default behaviour is dependency=infinity, i.e the runtime components remains. +%% We also test here that we can reconnect to the runtime. +running_alone_dist_1(suite) -> []; +running_alone_dist_1(doc) -> + [""]; +running_alone_dist_1(Config) when is_list(Config) -> + ?l {ok,_Pid1}=inviso:start(), % Start a control component. + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,[]), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + ?l shutdown=inviso:stop(), % Stop the control component! + ?l undefined=whereis(inviso_c), + timer:sleep(3000), % How long shall we wait? :-) + ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, + Nodes), + ?l {ok,_Pid2}=inviso:start(), + ?l {ok,NodeResults2}=inviso:add_nodes(Nodes,b_ref,[]), + ?l true=check_noderesults(Nodes,{ok,{adopted,new,running,a_ref}},NodeResults2), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Test of the dependency mechanism in the runtime component. +%% Test that the runtime components terminates after the specified 5000 ms. +running_alone_dist_2(suite) -> []; +running_alone_dist_2(doc) -> + [""]; +running_alone_dist_2(Config) when is_list(Config) -> + ?l {ok,_Pid1}=inviso:start(), % Start a control component. + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,[{dependency,5000}]), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + ?l shutdown=inviso:stop(), % Stop the control component! + ?l undefined=whereis(inviso_c), + timer:sleep(2000), + ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, + Nodes), + timer:sleep(4000), % Now they shall be dead! + ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt]) end, + Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Test of the dependency mechanism in the runtime component. +%% Test that the runtime components terminates after the specified 5000 ms. +running_alone_dist_3(suite) -> []; +running_alone_dist_3(doc) -> + [""]; +running_alone_dist_3(Config) when is_list(Config) -> + ?l {ok,_Pid1}=inviso:start(), % Start a control component. + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,[{dependency,1000}]), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + ?l {ok,NodeResults2}=inviso:change_options(Nodes,[{dependency,5000}]), + ?l true=check_noderesults(Nodes,ok,NodeResults2), + ?l shutdown=inviso:stop(), % Stop the control component! + ?l undefined=whereis(inviso_c), + timer:sleep(3000), + ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, + Nodes), + timer:sleep(3000), % Now they shall be dead! + ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt]) end, + Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Test of the dependency mechanism in the runtime component. +%% Test that the runtime components terminates after the specified 5000 ms, +%% like we did in running_alone_dist_2. But now we also start tracing and checks +%% that all inviso processes actually disappears when the time-out is reached. +running_alone_dist_4(suite) -> []; +running_alone_dist_4(doc) -> + [""]; +running_alone_dist_4(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + %% Start some tracing! + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataFun= + fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf_ra4"++atom_to_list(N)])}}, + {ti,{file,filename:join([PrivDir,"tf_ra4_"++atom_to_list(N)++".ti"])}}]} + end, + TracerDataList=lists:map(TracerDataFun,Nodes), + start_and_init_tracing2(Nodes, + [{dependency,5000}], + TracerDataList, + {ok,[{trace_log,ok},{ti_log,ok}]}), + + ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, + Nodes), + ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt_meta])) end, + Nodes), + %% Stop control component and wait for the runtimes to terminate after + %% running alone timer has expired. + ?l shutdown=inviso:stop(), % Stop the control component! + ?l undefined=whereis(inviso_c), + timer:sleep(2000), + ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, + Nodes), + ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt_meta])) end, + Nodes), + timer:sleep(4000), % Now they shall be dead! + ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt]) end, + Nodes), + ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt_meta]) end, + Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Test of the dependency mechanism in the runtime component. +%% Test that the runtime components terminates imeediately when the control +%% component is stopped. Check that all processes are gone. +running_alone_dist_5(suite) -> []; +running_alone_dist_5(doc) -> + [""]; +running_alone_dist_5(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + %% Start some tracing! + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataFun= + fun(N)->{N,[{trace,{file,filename:join([PrivDir,"tf_ra5"++atom_to_list(N)])}}, + {ti,{file,filename:join([PrivDir,"tf_ra5_"++atom_to_list(N)++".ti"])}}]} + end, + TracerDataList=lists:map(TracerDataFun,Nodes), + start_and_init_tracing2(Nodes, + [{dependency,0}], + TracerDataList, + {ok,[{trace_log,ok},{ti_log,ok}]}), + + ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt])) end, + Nodes), + ?l lists:foreach(fun(N)->true=is_pid(rpc:call(N,erlang,whereis,[inviso_rt_meta])) end, + Nodes), + %% Stop control component and check that all runtime component processes have + %% terminate more or less immediately afterwards, since dependency==0. + ?l shutdown=inviso:stop(), % Stop the control component! + timer:sleep(100), + ?l undefined=whereis(inviso_c), + timer:sleep(500), + ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt]) end, + Nodes), + ?l lists:foreach(fun(N)->undefined=rpc:call(N,erlang,whereis,[inviso_rt_meta]) end, + Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Test of the overload protection mechanism. The mechanism checks +%% for overload using the callback approximately at the interval specified. +%% Check that it does not start protection until start of tracing. +overload_dist_1(suite) -> []; +overload_dist_1(doc) -> + [""]; +overload_dist_1(Config) when is_list(Config) -> + ?l {ok,_Pid1}=inviso:start(), % Start a control component. + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + ?l lists:foreach(fun(N)->true=rpc:call(N,ets,insert,[inviso_sideeffect_tab,{ovl1,0}]) end, + Nodes), % Initiate the counter. + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes, + a_ref, + [{overload,{{?MODULE,overload1},500}}]), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + timer:sleep(1000), % Give the loadcheck time to perform. + ?l [{_,0}]=ets:lookup(inviso_sideeffect_tab,ovl1), % Nothing should have happened. + + %% Overload check shall not start until we start tracing. + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList=lists:map(fun(N)->{N,[{trace, + {file,filename:join([PrivDir, + "tf_ovl1."++atom_to_list(N) + ])}}]} + end, + Nodes), + ?l {ok,NodeResults2}=inviso:init_tracing(TracerDataList), + ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok}]},NodeResults2), + timer:sleep(1500), % Give the loadcheck time to perform. + ?l [{_,N}]=ets:lookup(inviso_sideeffect_tab,ovl1), + ?l true=(N>=2), % After 1,5 seconds, at least 2 checks. + + %% Now change options and remove overload checking! + ?l {ok,NodeResults3}=inviso:change_options(Nodes,[overload]), + ?l true=check_noderesults(Nodes,ok,NodeResults3), + ?l [{_,N2}]=ets:lookup(inviso_sideeffect_tab,ovl1), + timer:sleep(1000), + ?l [{_,N2}]=ets:lookup(inviso_sideeffect_tab,ovl1), % No more loadchecks! + + stop_tracing(Nodes), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Test of the overload protection mechanism. In this case we focus +%% in that the init and remove functions are carried out at change_options and +%% when starting and stoping the runtime component. +overload_dist_2(suite) -> []; +overload_dist_2(doc) -> + [""]; +overload_dist_2(Config) when is_list(Config) -> + ?l {ok,_Pid1}=inviso:start(), % Start a control component. + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes, + a_ref, + [{overload,{{?MODULE,overload2}, + 500, + {?MODULE,overload2i,[]}, + {?MODULE,overload2r,[]}}}]), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + ?l [{_,0}]=ets:lookup(inviso_sideeffect_tab,ovl2), + + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList=lists:map(fun(N)->{N,[{trace, + {file,filename:join([PrivDir, + "tf_ovl2."++atom_to_list(N) + ])}}]} + end, + Nodes), + ?l {ok,NodeResults2}=inviso:init_tracing(TracerDataList), + ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok}]},NodeResults2), + timer:sleep(1500), % Give the loadcheck time to perform. + ?l [{_,N}]=ets:lookup(inviso_sideeffect_tab,ovl2), + io:format("� is:~p~n",[N]), + ?l true=(N>=2), % After 1,5 seconds, at least 2 checks. + ?l {ok,NodeResults3}=inviso:change_options(Nodes,[{overload,{{?MODULE,overload3}, + 500, + {?MODULE,overload3i,[]}, + {?MODULE,overload3r,[]}}}]), + ?l true=check_noderesults(Nodes,ok,NodeResults3), + ?l []=ets:lookup(inviso_sideeffect_tab,ovl2), + timer:sleep(1500), + ?l [{_,N2}]=ets:lookup(inviso_sideeffect_tab,ovl3), + ?l true=(N2>=2), % After 1,5 seconds, at least 2 checks. + stop_tracing(Nodes), + ?l []=ets:lookup(inviso_sideeffect_tab,ovl3r), % Remove function shall not be called. + ?l [{_,N3}]=ets:lookup(inviso_sideeffect_tab,ovl3), + timer:sleep(1000), % Check that overloadchecking has stopped. + ?l [{_,N3}]=ets:lookup(inviso_sideeffect_tab,ovl3), + stop(Nodes), + ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,ovl3r],[{ovl3r,done}],20), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Test of the overload protections mechanism. Here we focus on testing +%% that if overload is reached tracing is really suspended. +overload_dist_3(suite) -> []; +overload_dist_3(doc) -> + [""]; +overload_dist_3(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList= + lists:map(fun(N)->{N,[{trace,{file,filename:join([PrivDir, + "tf_ovl3."++atom_to_list(N)])}}, + {ti,{file,filename:join([PrivDir, + "tf_ovl3_ti."++atom_to_list(N)])}}]} + end, + Nodes), + ?l lists:foreach(fun(N)-> + true=rpc:call(N,ets,insert,[inviso_sideeffect_tab,{ovl4,0}]) + end, + Nodes), + start_and_init_tracing2(Nodes, + [{overload,{{?MODULE,overload4},500}}], + TracerDataList, + {ok,[{trace_log,ok},{ti_log,ok}]}), + activate_local_tracing(Nodes), + activate_meta_tracing(Nodes), + activate_traceflags(Nodes), + timer:sleep(600), + ?l [{_,N1}]=ets:lookup(inviso_sideeffect_tab,ovl4), + ?l true=(N1>=1), % Overload check has been done! + ?l Node=node(), + ?l {ok,[{Node,{ok,{tracing,running}}}]}=inviso:get_status([node()]), + ?l true=ets:insert(inviso_sideeffect_tab,{ovl4_suspend,true}), + timer:sleep(600), + ?l {ok,[{Node,{ok,{tracing,{suspended,test}}}}]}=inviso:get_status([node()]), + ?l [{_,N2}]=ets:lookup(inviso_sideeffect_tab,ovl4), + ?l {flags,[]}=erlang:trace_info(whereis(inviso_test_proc),flags), + ?l {meta,false}=erlang:trace_info({lists,module_info,0},meta), + ?l {traced,local}=erlang:trace_info({code,which,1},traced), + ?l true=(is_pid(whereis(inviso_rt_meta))), + ?l true=ets:delete(inviso_sideeffect_tab,ovl4_suspend), + timer:sleep(600), + ?l [{_,N2}]=ets:lookup(inviso_sideeffect_tab,ovl4), % No checking while suspended! + ?l {ok,[{Node,ok}]}=inviso:cancel_suspension([node()]), + ?l {ok,NodeResults1}=inviso:get_status(Nodes), + ?l true=check_noderesults(Nodes,{ok,{tracing,running}},NodeResults1), + timer:sleep(600), + ?l [{_,N3}]=ets:lookup(inviso_sideeffect_tab,ovl4), + ?l true=(N3>N2), + ?l deactivate_local_tracing(Nodes), + ?l stop_tracing(Nodes), + ?l stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE. Test that the overload mechanism is triggered by to the runtime +%% component incomming messages, and nothing else. +overload_dist_4(suite) -> []; +overload_dist_4(doc) -> + [""]; +overload_dist_4(Config) when is_list(Config) -> + ?l {ok,_Pid1}=inviso:start(), % Start a control component. + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes, + a_ref, + [{overload,{{?MODULE,overload5}, + infinity, + {?MODULE,overload5i,[]}, + {?MODULE,overload5r,[]}}}]), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + ?l [{_,0}]=ets:lookup(inviso_sideeffect_tab,ovl5), + + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList=lists:map(fun(N)->{N,[{trace, + {file,filename:join([PrivDir, + "tf_ovl4."++atom_to_list(N) + ])}}]} + end, + Nodes), + ?l {ok,NodeResults2}=inviso:init_tracing(TracerDataList), + ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok}]},NodeResults2), + timer:sleep(2000), % Give the loadcheck time to perform. + ?l [{_,N}]=ets:lookup(inviso_sideeffect_tab,ovl5), + ?l true=(N==0), % And nothing shall have happend! + %% Now we send a message to the inviso_rt, then the load check function + %% shall be called. + ?l whereis(inviso_rt) ! test_of_loadcheck, + timer:sleep(200), % Make sure the inviso_rt gets scheduled. + ?l [{_,1}]=ets:lookup(inviso_sideeffect_tab,ovl5), + stop_tracing(Nodes), + ?l []=ets:lookup(inviso_sideeffect_tab,ovl5r), % Remove function shall not be called. + ?l [{_,N3}]=ets:lookup(inviso_sideeffect_tab,ovl5), + ?l whereis(inviso_rt) ! test_of_loadcheck, + timer:sleep(1000), % Check that overloadchecking has stopped. + ?l [{_,N3}]=ets:lookup(inviso_sideeffect_tab,ovl5), + stop(Nodes), + ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,ovl5r],[{ovl5r,done}],20), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE. Test that the overload mechanism correctly calculates remaining time +%% to next load check if a message comes into the runtime component "interupting" +%% the waiting for loadcheck timeout. (Loadcheck timeout is implemented as an after +%% in the receive). +overload_dist_5(suite) -> []; +overload_dist_5(doc) -> + [""]; +overload_dist_5(Config) when is_list(Config) -> + ?l {ok,_Pid1}=inviso:start(), % Start a control component. + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + ?l lists:foreach(fun(N)->true=rpc:call(N,ets,insert,[inviso_sideeffect_tab,{ovl6,0}]) end, + Nodes), % Initiate the counter. + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes, + a_ref, + [{overload,{{?MODULE,overload6},1000}}]), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + %% Overload check shall not start until we start tracing. + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList=lists:map(fun(N)->{N,[{trace, + {file,filename:join([PrivDir, + "tf_ovl5."++atom_to_list(N) + ])}}]} + end, + Nodes), + ?l {ok,NodeResults2}=inviso:init_tracing(TracerDataList), + ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok}]},NodeResults2), + ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,ovl6],[{ovl6,2}],25), + %% Now we know that exactly 2 checks have been made. Try to Distract the runtime :-) + ?l inviso_rt:state(whereis(inviso_rt)), % Make it have to receive a message. + timer:sleep(500), + ?l [{_,2}]=ets:lookup(inviso_sideeffect_tab,ovl6), % Should still be 2. + timer:sleep(600), + ?l [{_,3}]=ets:lookup(inviso_sideeffect_tab,ovl6), % We expect yet one check. + timer:sleep(1100), + ?l [{_,4}]=ets:lookup(inviso_sideeffect_tab,ovl6), + + stop_tracing(Nodes), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + + +%% TEST CASE: Test of the subscription mechanism. +subscribe_dist_1(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + Pid=spawn(?MODULE,inviso_msg_collector,[]), + CtrlPid=whereis(inviso_c), + + ?l {ok,_Pid}=inviso:start(), % Start a control component. + ?l ok=inviso:subscribe(Pid), + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,[]), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + ?l {ok,NodeResults2}=inviso:get_status(Nodes), + ?l true=check_noderesults(Nodes,{ok,{new,running}},NodeResults2), + check_msg_collector(Nodes, + fun({inviso_event,CP,_,{connected,N,{_Tag,{idle,running}}}}) + when CP==CtrlPid -> + {true,N}; + (_) -> + false + end, + 13), + TracerDataList=lists:map(fun(N)->{N,{file, + filename:join([PrivDir, + "tf_sub1"++atom_to_list(N)])}} + end, + Nodes), + ?l {ok,NodeResults3}=inviso:init_tracing(TracerDataList), + ?l true=check_noderesults(Nodes,{ok,[{trace_log,ok}]},NodeResults3), + check_msg_collector(Nodes, + fun({inviso_event,CP,_,{state_change,N,{tracing,running}}}) + when CP==CtrlPid -> + {true,N}; + (_) -> + false + end, + 13), + ?l {ok,NodeResults4}=inviso:suspend(Nodes,test), + ?l true=check_noderesults(Nodes,ok,NodeResults4), + check_msg_collector(Nodes, + fun({inviso_event,CP,_,{state_change,N,{tracing,{suspended,test}}}}) + when CP==CtrlPid -> + {true,N}; + (_) -> + false + end, + 13), + ?l [RNode|_]=RemoteNodes, + ?l RInvisoPid=rpc:call(RNode,erlang,whereis,[inviso_rt]), + ?l rpc:call(RNode,erlang,exit,[RInvisoPid,kill]), + check_msg_collector([RNode], + fun({inviso_event,CP,_,{disconnected,N,_Info}}) + when CP==CtrlPid -> + {true,N}; + (_) -> + false + end, + 11), + + ?l {ok,_NodeResults5}=inviso:stop_tracing(Nodes), + ?l {ok,_NodeResults6}=inviso:stop_nodes(Nodes), + ?l shutdown=inviso:stop(), + ok. +%% ----------------------------------------------------------------------------- + + +%% TEST CASE: fetch_log test of single straight trace_log file in distributed +%% environment. +fetch_log_dist_trace_1(suite) -> []; +fetch_log_dist_trace_1(doc) -> + ["fetch_log test of single straight trace_log file in distributed" + "environment."]; +fetch_log_dist_trace_1(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList=lists:map(fun(N)->{N,[{trace,{file,filename:join([PrivDir, + "testfile1."++ + atom_to_list(N) + ])}}]} end, + Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), + + %% Put some output in the logs. + ?l inviso:tp(Nodes,math,module_info,0,[]), + ?l inviso:tf(Nodes,all,[call]), + ?l lists:foreach(fun(N)->rpc:call(N,math,module_info,[]) end,Nodes), + + stop_tracing(Nodes), + {H,M,S}=time(), + FetchToDir=filename:join([PrivDir, + "fetch_log_test1_"++integer_to_list(H)++"_"++ + integer_to_list(M)++"_"++integer_to_list(S)]), + ?l ok=file:make_dir(FetchToDir), + ?l {ok,NodeResults}=inviso:fetch_log(RemoteNodes,FetchToDir,"p1"), + io:format("~p~n",[NodeResults]), + ?l true=check_noderesults(RemoteNodes, + fun({N,{complete,[{trace_log,[{ok,File}]},{ti_log,[]}]}}) -> + ?l File="p1testfile1."++atom_to_list(N), + true; + (_)-> + false + end, + NodeResults), + ?l ON=filename:join(PrivDir,"testfile1."), + ?l FN=filename:join(FetchToDir,"p1testfile1."), + ?l lists:foreach(fun(N)-> + {ok,#file_info{size=Size}}= + file:read_file_info(ON++atom_to_list(N)), + {ok,#file_info{size=Size}}= + file:read_file_info(FN++atom_to_list(N)) + end, + RemoteNodes), + %% Now we wish to see that we get an incomplete if we try to fetch to a + %% directory that does not exist. + ?l FetchToErrorDir=filename:join([PrivDir,nonexistingingdir]), + ?l {ok,NodeResults2}=inviso:fetch_log(RemoteNodes,FetchToErrorDir,"p1"), + ?l io:format("NodeResults2:~w~n",[NodeResults2]), + ?l true=check_noderesults(RemoteNodes, + fun({_,{incomplete,_}}) -> + true; + (_)-> + false + end, + NodeResults2), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +fetch_log_dist_trace_2(suite) -> []; +fetch_log_dist_trace_2(doc) -> + [""]; +fetch_log_dist_trace_2(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + + {H,M,S}=time(), + ?l Name="wrap"++integer_to_list(H)++"_"++integer_to_list(M)++"_"++integer_to_list(S), + ?l BaseName=filename:join(PrivDir,Name), + Fun=fun(N)->{N,[{trace,{file,{BaseName++atom_to_list(N),wrap,".log",512,2}}}, + {ti,{file,BaseName++"_ti_"++atom_to_list(N)++".ti"}}]} + end, + ?l TracerDataList=lists:map(Fun,Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), + fill_and_reach_two_wrapfiles(PrivDir,"^"++Name,Nodes), + + stop_tracing(Nodes), + FetchToDir=filename:join([PrivDir, + "fetch_log_test2_"++integer_to_list(H)++"_"++ + integer_to_list(M)++"_"++integer_to_list(S)]), + ?l ok=file:make_dir(FetchToDir), + ?l {ok,NodeResults}=inviso:fetch_log(RemoteNodes,FetchToDir,"p1"), + io:format("~p~n",[NodeResults]), + CheckFun=fun({N,{complete,[{trace_log,FileResults1},{ti_log,[{ok,TiFile}]}]}}) -> + Fun2=fun({ok,File}) -> + {match,1,_}= + regexp:first_match(File, + "^"++"p1"++Name++atom_to_list(N)), + true; + (_) -> + false + end, + ?l true=lists:all(Fun2,FileResults1), + ?l TiFile="p1"++Name++"_ti_"++atom_to_list(N)++".ti", + true; + (_)-> + false + end, + ?l true=check_noderesults(RemoteNodes,CheckFun,NodeResults), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +fetch_log_dist_trace_3(suite) -> []; +fetch_log_dist_trace_3(doc) -> + [""]; +fetch_log_dist_trace_3(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + + {H,M,S}=time(), + ?l Name="wrap2_"++integer_to_list(H)++"_"++integer_to_list(M)++"_"++integer_to_list(S), + ?l BaseName=filename:join(PrivDir,Name), + Fun=fun(N)->{N,[{trace,{file,{BaseName++atom_to_list(N),wrap,".log",512,2}}}, + {ti,{file,BaseName++"_ti_"++atom_to_list(N)++".ti"}}]} + end, + ?l TracerDataList=lists:map(Fun,Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), + fill_and_reach_two_wrapfiles(PrivDir,"^"++Name,Nodes), + + stop_tracing(Nodes), + FetchToDir=filename:join([PrivDir, + "fetch_log_test3_"++integer_to_list(H)++"_"++ + integer_to_list(M)++"_"++integer_to_list(S)]), + ?l ok=file:make_dir(FetchToDir), + ?l {ok,NodeResults1}=inviso:list_logs(Nodes), + CheckFun=fun({N,{ok,[{trace_log,PrivDir2,[F1,F2]},{ti_log,PrivDir2,[F3]}]}})-> + PrivDir2=PrivDir, + RegExp="^"++Name++atom_to_list(N)++"[0-9]+"++"\.log", + {match,1,_}=regexp:first_match(F1,RegExp), + {match,1,_}=regexp:first_match(F2,RegExp), + F3=Name++"_ti_"++atom_to_list(N)++".ti", + true; + (_) -> + false + end, + ?l true=check_noderesults(Nodes,CheckFun,NodeResults1), + ?l NodeFileSpecList=lists:map(fun({N,{ok,L}})->{N,L} end, + lists:keydelete(node(),1,NodeResults1)), + ?l {ok,NodeResults2}=inviso:fetch_log(NodeFileSpecList,FetchToDir,"p1"), +io:format("~p~n",[NodeResults2]), + CheckFun2=fun({N,{complete,[{trace_log,FileResults1},{ti_log,[{ok,TiFile}]}]}}) -> + Fun2=fun({ok,File}) -> + {match,1,_}= + regexp:first_match(File, + "^"++"p1"++Name++atom_to_list(N)), + true; + (_) -> + false + end, + ?l true=lists:all(Fun2,FileResults1), + ?l TiFile="p1"++Name++"_ti_"++atom_to_list(N)++".ti", + true; + (_)-> + false + end, + ?l true=check_noderesults(RemoteNodes,CheckFun2,NodeResults2), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +fetch_log_dist_error_1(suite) -> []; +fetch_log_dist_error_1(doc) -> + [""]; +fetch_log_dist_error_1(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + ?l {ok,_Pid}=inviso:start(), % Start a control component. + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + ?l {ok,NodeResults2}=inviso:fetch_log(RemoteNodes,"foo","bar"), +io:format("~p~n",[NodeResults2]), + ?l true=check_noderesults(RemoteNodes, + fun({_N,{error,no_tracerdata}})->true; + (_)->false + end, + NodeResults2), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +fetch_log_dist_error_2(suite) -> []; +fetch_log_dist_error_2(doc) -> + [""]; +fetch_log_dist_error_2(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + PrivDir=filename:join(?config(priv_dir,Config),""), + ?l {ok,_Pid}=inviso:start(), % Start a control component. + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + ?l NodeLogList=lists:map(fun(N)->{N,[{trace_log, + PrivDir, + ["f1,fil","f2.fil"]}, + {ti_log, + PrivDir, + ["f.ti"]}]} + end, + RemoteNodes), + ?l {ok,NodeResults2}=inviso:fetch_log(NodeLogList,"foo","bar"), + io:format("~p~n",[NodeResults2]), + ?l true=check_noderesults(RemoteNodes, + fun({_N,{incomplete,_}}) -> + true; + (_) -> + false + end, + NodeResults2), + ?l NodeTracerData=lists:map(fun(N)->{N, + [{trace,{file,filename:join(PrivDir,"foo")}}, + {ti,{file,filename:join(PrivDir,"bar.ti")}}]} + end, + RemoteNodes), + {ok,NodeResults3}=inviso:fetch_log(NodeTracerData,"foo","bar"), + io:format("~p~n",[NodeResults3]), +%% This should work this way. Now it says complete [], which is not entirely +%% incorrect. But to follow the sematics of when fetching named files should +%% say incomplete. +%% Must do some rework to make that work. No real danger leaving it this way +%% for now. +% ?l true=check_noderesults(RemoteNodes, +% fun({_N,{incomplete,_}}) -> +% true; +% (_) -> +% false +% end, +% NodeResults3), + stop(Nodes), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: This case tests that the log file merger merges files in the +%% correct order, based on the timestamps. +lfm_trace_dist_1(suite) -> []; +lfm_trace_dist_1(doc) -> + [""]; +lfm_trace_dist_1(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + [RNode1,RNode2|_]=RemoteNodes, + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList= + lists:map(fun(N)->{N,{file,filename:join([PrivDir,"lfm1_"++atom_to_list(N)])}} end, + Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), + activate_local_tracing(Nodes), + activate_traceflags(Nodes), + + {inviso_test_proc,RNode2} ! {apply,code,which,[lists]}, + timer:sleep(300), + {inviso_test_proc,RNode1} ! {apply,code,which,[lists]}, + timer:sleep(300), + {inviso_test_proc,RNode1} ! {apply,code,which,[lists]}, + timer:sleep(300), + inviso_test_proc ! {apply,code,which,[lists]}, + timer:sleep(300), + {inviso_test_proc,RNode2} ! {apply,code,which,[lists]}, + timer:sleep(300), + inviso_test_proc ! {apply,code,which,[lists]}, + + deactivate_traceflags(Nodes), + deactivate_local_tracing(Nodes), + stop_tracing(Nodes), + stop(Nodes), + + DestFile=filename:join(PrivDir,"lfm1_out.txt"), + ?l {ok,6}= + inviso_lfm:merge([{node(), + [{trace_log, + [filename:join(PrivDir,"lfm1_"++atom_to_list(node()))]}]}, + {RNode1, + [{trace_log, + [filename:join(PrivDir,"lfm1_"++atom_to_list(RNode1))]}]}, + {RNode2, + [{trace_log, + [filename:join(PrivDir,"lfm1_"++atom_to_list(RNode2))]}]}], + DestFile), + ?l {ok,FD}=file:open(DestFile,[read]), + ?l S1=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(RNode2),S1), + ?l S2=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(RNode1),S2), + ?l S3=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(RNode1),S3), + ?l S4=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(node()),S4), + ?l S5=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(RNode2),S5), + ?l S6=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(node()),S6), + ?l file:close(FD), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: Testing to the full extent that pid-mappings work with both +%% local and global registration. Also checks that pidmappings can be removed +%% and that consequently the mappings in the resulting merged file stops. +lfm_trace_ti_dist_2(suite) -> []; +lfm_trace_ti_dist_2(doc) -> + [""]; +lfm_trace_ti_dist_2(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + [RNode1,RNode2|_]=RemoteNodes, + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList= + lists:map(fun(N)->{N,[{trace,{file,filename:join(PrivDir,"lfm2_"++atom_to_list(N))}}, + {ti,{file,filename:join(PrivDir,"lfm2_ti_"++atom_to_list(N))}}]} + end, + Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok},{ti_log,ok}]}), + activate_local_tracing(Nodes), + activate_meta_tracing(Nodes), + activate_traceflags(Nodes), + + {inviso_test_proc,RNode2} ! {apply,code,which,[lists]}, + timer:sleep(300), + {inviso_test_proc,RNode1} ! {apply,code,which,[lists]}, + timer:sleep(300), + {inviso_test_proc,RNode1} ! {apply,code,which,[lists]}, + timer:sleep(300), + inviso_test_proc ! {apply,code,which,[lists]}, + timer:sleep(300), + + P2=spawn(RNode2,?MODULE,test_proc_loop,[]), + P1=spawn(RNode1,?MODULE,test_proc_loop,[]), + P0=spawn_link(?MODULE,test_proc_loop,[]), + ThisNode=node(), + ?l {ok,[{ThisNode,{ok,[1]}}]}=inviso:tf([node()],P0,[call,timestamp]), + ?l {ok,[{RNode1,{ok,[1]}}]}=inviso:tf([RNode1],P1,[call,timestamp]), + ?l {ok,[{RNode2,{ok,[1]}}]}=inviso:tf([RNode2],P2,[call,timestamp]), + P2 ! {apply,code,which,[lists]}, + timer:sleep(300), + P1 ! {apply,code,which,[lists]}, + timer:sleep(300), + P0 ! {apply,code,which,[lists]}, + timer:sleep(300), + + P3=spawn(RNode2,?MODULE,test_proc_loop,[]), + ?l yes=global:register_name(inviso_test_proc_globalname,P3), + ?l {ok,[{RNode2,{ok,[1]}}]}=inviso:tf([RNode2],P3,[call,timestamp]), + timer:sleep(300), + P3 ! {apply,code,which,[lists]}, + timer:sleep(300), + + P4=rpc:call(RNode1,erlang,whereis,[inviso_test_proc]), + ?l true=rpc:call(RNode1,erlang,unregister,[inviso_test_proc]), + timer:sleep(300), + P4 ! {apply,code,which,[lists]}, + timer:sleep(300), + + ?l true=rpc:call(RNode1,erlang,register,[inviso_test_proc,P4]), + + ?l global:unregister_name(inviso_test_proc_globalname), + timer:sleep(300), + ?l P3 ! {apply,code,which,[lists]}, + timer:sleep(300), + + deactivate_traceflags(Nodes), + deactivate_local_tracing(Nodes), + stop_tracing(Nodes), + stop(Nodes), + + DestFile=filename:join(PrivDir,"lfm2_out.txt"), + ?l {ok,10}= + inviso_lfm:merge([ + {node(), + [{trace_log, + [filename:join(PrivDir,"lfm2_"++atom_to_list(node()))]}, + {ti_log, + [filename:join(PrivDir,"lfm2_ti_"++atom_to_list(node()))]}]}, + {RNode1, + [{trace_log, + [filename:join(PrivDir,"lfm2_"++atom_to_list(RNode1))]}, + {ti_log, + [filename:join(PrivDir,"lfm2_ti_"++atom_to_list(RNode1))]}]}, + {RNode2, + [{trace_log, + [filename:join(PrivDir,"lfm2_"++atom_to_list(RNode2))]}, + {ti_log, + [filename:join(PrivDir,"lfm2_ti_"++atom_to_list(RNode2))]}]} + ], + DestFile), + ?l {ok,FD}=file:open(DestFile,[read]), + ?l S1=io:get_line(FD,""), +io:format("S1 is:~p~n",[S1]), + ?l true=lists:prefix(atom_to_list(RNode2)++" [inviso_test_proc",S1), + ?l S2=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(RNode1)++" [inviso_test_proc",S2), + ?l S3=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(RNode1)++" [inviso_test_proc",S3), + ?l S4=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(node())++" [inviso_test_proc",S4), + ?l S5=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(RNode2)++" []",S5), + ?l S6=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(RNode1)++" []",S6), + ?l S7=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(node())++" []",S7), + ?l S8=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(RNode2)++" [{global,inviso_test_proc_globalname}]",S8), + ?l S9=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(RNode1)++" []",S9), + ?l S10=io:get_line(FD,""), + ?l true=lists:prefix(atom_to_list(RNode2)++" []",S10), + ?l file:close(FD), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: This tests that the wrapset sorter works. +handle_logfile_sort_wrapset(suite) -> []; +handle_logfile_sort_wrapset(doc) -> + [""]; +handle_logfile_sort_wrapset(Config) when is_list(Config) -> + File0="prefix10.fil", + File1="prefix11.fil", + File2="prefix12.fil", + File3="prefix13.fil", + ?l [File0,File1,File2,File3]= + inviso_lfm_tpfreader:handle_logfile_sort_wrapset([File2,File1,File0,File3]), + File5="prefix15.fil", + ?l [File5,File0,File1,File2,File3]= + inviso_lfm_tpfreader:handle_logfile_sort_wrapset([File2,File5,File1,File0,File3]), + ok. +%% ----------------------------------------------------------------------------- + +%% TEST CASE: This case tests that the regexp mechanism in the inviso_rt_lib can +%% find modules using regexps and that its only_loaded mechanism works. +%% This test case can not be run when using cover because cover will make the +%% modules no longer loaded from the path containing "runtime_tools". +expand_regexp_dist_1(suite) -> []; +expand_regexp_dist_1(doc) -> + [""]; +expand_regexp_dist_1(Config) when is_list(Config) -> + case ?t:is_cover() of + true -> + {skip,"Cover is running"}; + false -> + expand_regexp_dist_1_nocover(Config) + end. + +expand_regexp_dist_1_nocover(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + [RNode1|_]=RemoteNodes, + ?l NodeResults1=inviso_rt_lib:expand_regexp(Nodes,"^inviso_rt.*",[]), + ?l L1=length(Nodes), + ?l L1=length(NodeResults1), + ?l true=lists:all(fun({_,Mods})-> + ?l 3=length(Mods), + ?l true=lists:member(inviso_rt,Mods), + ?l true=lists:member(inviso_rt_lib,Mods), + ?l true=lists:member(inviso_rt_meta,Mods), + true; + (_) -> + false + end, + NodeResults1), + %% Check the dir-option. In the following inviso_tool_lib shall not be found. + ?l NodeResults2=inviso_rt_lib:expand_regexp(Nodes,"runtime_tools","invi.*lib.*",[]), +?l io:format("NodeResults2:~w~n",[NodeResults2]), + ?l L1=length(NodeResults2), % Same number of nodes replying. + ?l true=lists:all(fun({_,Mods})-> + 2=length(Mods), + true=lists:member(inviso_as_lib,Mods), + true=lists:member(inviso_rt_lib,Mods), + true; + (_) -> + false + end, + NodeResults2), + ?l [{RNode1,[]}]= + inviso_rt_lib:expand_regexp([RNode1],"^inviso_testmodule1.*",[only_loaded]), + ?l [{RNode1,[inviso_testmodule1_foo]}]= + inviso_rt_lib:expand_regexp([RNode1],"^inviso_testmodule1.*",[]), + ok. +%% ----------------------------------------------------------------------------- + + +only_loaded_dist_1(suite) -> []; +only_loaded_dist_1(doc) -> + [""]; +only_loaded_dist_1(Config) when is_list(Config) -> + RemoteNodes=get_remotenodes_config(Config), + Nodes=[node()|RemoteNodes], + [RNode1|_]=RemoteNodes, + PrivDir=filename:join(?config(priv_dir,Config),""), + TracerDataList= + lists:map(fun(N)->{N,[{trace,{file,filename:join(PrivDir,"ol_1_"++atom_to_list(N))}}]} + end, + Nodes), + start_and_init_tracing2(Nodes,[],TracerDataList,{ok,[{trace_log,ok}]}), + ?l false=rpc:call(RNode1,erlang,module_loaded,[inviso_testmodule1_foo]), + ?l {ok,[{RNode1,{ok,[0]}}]}= + inviso:tpl([RNode1],inviso_testmodule1_foo,'_','_',[],[only_loaded]), + ?l false=rpc:call(RNode1,erlang,module_loaded,[inviso_testmodule1_foo]), + ?l {ok,[{RNode1,{ok,[3]}}]}= + inviso:tpl([RNode1],inviso_testmodule1_foo,'_','_',[],[]), + stop_tracing(Nodes), + stop(Nodes), + ok. + + +%% ============================================================================== +%% Common functions setting up inviso. +%% ============================================================================== + +%% Starts controlcomponent and adds runtime components on the nodes specified. +%% Also initiates tracing on the nodes. +start_and_init_tracing1(Nodes,Options,TracerData,Reply) when is_list(Nodes) -> + ?l {ok,_Pid}=inviso:start(), % Start a control component. + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,Options), + io:format("~p~n",[NodeResults1]), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + ?l {ok,NodeResults2}=inviso:get_status(Nodes), + ?l true=check_noderesults(Nodes,{ok,{new,running}},NodeResults2), + ?l {ok,NodeResults3}=inviso:init_tracing(Nodes,TracerData), + ?l true=check_noderesults(Nodes,Reply,NodeResults3), + ok. +start_and_init_tracing2(Nodes,Options,TracerDataList,Reply) -> + ?l {ok,_Pid}=inviso:start(), % Start a control component. + ?l {ok,NodeResults1}=inviso:add_nodes(Nodes,a_ref,Options), + io:format("~p~n",[NodeResults1]), + ?l true=check_noderesults(Nodes,{ok,new},NodeResults1), + ?l {ok,NodeResults2}=inviso:get_status(Nodes), + ?l true=check_noderesults(Nodes,{ok,{new,running}},NodeResults2), + ?l {ok,NodeResults4}=inviso:get_tracerdata(Nodes), + ?l true=check_noderesults(Nodes,{ok,no_tracerdata},NodeResults4), + ?l {ok,NodeResults3}=inviso:init_tracing(TracerDataList), + io:format("Tracerdatalist:~p~n",[TracerDataList]), + ?l true=check_noderesults(Nodes,Reply,NodeResults3), + + ?l Fun1=fun({N,{ok,TD}}) when is_list(TD)-> + ?l {value,{trace,Trace}}=lists:keysearch(trace,1,TD), + ?l {value,{N,TD2}}=lists:keysearch(N,1,TracerDataList), + ?l true=lists:member({trace,Trace},TD2), + %% Check that the trace file really exists. + ?l case Trace of % Trace={file,FilePortParameters} + {file,FileName1} when is_list(FileName1) -> + ?l {ok,_}=rpc:call(N,file,read_file_info,[FileName1]); + _ -> % This should be extended with more cases. + true + end, + ?l case lists:keysearch(ti,1,TD2) of + {value,{_,Ti}} -> % Ok, we have ti too. + ?l {value,{_,Ti}}=lists:keysearch(ti,1,TD), + ?l FileName2=element(2,Ti), + ?l {ok,_}=rpc:call(N,file,read_file_info,[FileName2]), + true; + false -> % No ti, we are done now. + true + end; + ({N,{ok,{file,FileName}}}) -> + ?l {value,{N,{file,FileName}}}=lists:keysearch(N,1,TracerDataList), + ?l {ok,_}=rpc:call(N,file,read_file_info,[FileName]), + true; + ({N,{ok,LogTD}}) -> % The case using a fun. + ?l {value,{N,LogTD}}=lists:keysearch(N,1,TracerDataList), + true + end, + ?l {ok,NodeResults5}=inviso:get_tracerdata(Nodes), + ?l true=check_noderesults(Nodes,Fun1,NodeResults5), + ok. +%% ------------------------------------------------------------------------------ + +%% Stops tracing on Nodes. +stop_tracing(Nodes) when is_list(Nodes) -> + ?l {ok,NodeResults1}=inviso:stop_tracing(Nodes), + ?l true=check_noderesults(Nodes,{ok,idle},NodeResults1), + ?l {ok,NodeResults2}=inviso:get_status(Nodes), + ?l true=check_noderesults(Nodes,{ok,{idle,running}},NodeResults2), + %% The implementation says that the meta tracer shall be stopped when + %% tracing is stopped. Check that. + ?l lists:foreach(fun(N)-> + ok=poll(erlang,whereis,[inviso_rt_meta],undefined,20) + end, + Nodes). +%% ------------------------------------------------------------------------------ + +%% Stops the runtime components on Nodes and stops the control component at this +%% Erlang node. +stop(Nodes) when is_list(Nodes) -> + ?l true=check_on_nodes(Nodes,erlang,whereis,[inviso_rt],fun(P) when is_pid(P)->true end), + ?l {ok,NodeResults}=inviso:stop_nodes(Nodes), + ?l true=check_noderesults(Nodes,ok,NodeResults), + ?l true=check_on_nodes(Nodes,erlang,whereis,[inviso_rt],fun(undefined)->true end), + ?l true=is_pid(whereis(inviso_c)), + ?l shutdown=inviso:stop(), + ?l ok=poll(erlang,whereis,[inviso_c],undefined,20). +%% ------------------------------------------------------------------------------ + +%% Help function activating local tracing. +activate_local_tracing(Nodes) when is_list(Nodes) -> + ?l true=check_on_nodes(Nodes, + erlang, + trace_info, + [{code,which,1},traced], + {traced,false}), + ?l {ok,NodeResults}=inviso:tpl(Nodes,code,which,1,[]), + ?l true=check_noderesults(Nodes,fun({_,{ok,[1]}})->true end,NodeResults), + ?l true=check_on_nodes(Nodes, + erlang, + trace_info, + [{code,which,1},traced], + {traced,local}). +%% ------------------------------------------------------------------------------ + +%% Help function activating global tracing. +activate_global_tracing(Nodes) when is_list(Nodes) -> + ?l true=check_on_nodes(Nodes, + erlang, + trace_info, + [{code,get_path,0},traced], + {traced,false}), + ?l {ok,NodeResults}=inviso:tp(Nodes,code,get_path,0,[]), + ?l true=check_noderesults(Nodes,fun({_,{ok,[1]}})->true end,NodeResults), + ?l true=check_on_nodes(Nodes, + erlang, + trace_info, + [{code,get_path,0},traced], + {traced,global}). +%% ------------------------------------------------------------------------------ + + +%% Help function activating local tracing and using a regexp to point out modules. +%% Returns the structure of modules and functions that were activated. Must be used +%% when deactivating. +activate_global_tracing_regexp(Nodes) when is_list(Nodes) -> + %% First find out which modules will be effected. + ?l Mods1=inviso_rt_lib:expand_regexp("application.*",[]), + ?l true=(length(Mods1)>1), % Should find more than one module! + ?l Funcs1=lists:foldl(fun(M,Acc)->[{M,M:module_info(exports)}|Acc] end,[],Mods1), + %% Check that these functions are not traced. + io:format("Modules:~w~n",[Mods1]), + ?l {ok,NodeResults}=inviso:tp(Nodes,"application.*",'_','_',[],[]), + io:format("Here 2~w~n",[NodeResults]), + ?l N=lists:foldl(fun({_,L1},A1)->lists:foldl(fun(_,A2)->A2+1 end,A1,L1) end,0,Funcs1), + ?l true=check_noderesults(Nodes,fun({_,{ok,L}})-> N==lists:sum(L) end,NodeResults), + io:format("Here 3~n",[]), + %% Check again! + ?l lists:foreach(fun({M,Funcs})-> + lists:foreach(fun({F,Arity})-> + true=check_on_nodes(Nodes, + erlang, + trace_info, + [{M,F,Arity},traced], + {traced,global}) + end, + Funcs) + end, + Funcs1), + Funcs1. +%% ------------------------------------------------------------------------------ + +%% Help function as above but uses the dir feature as well. +activate_global_tracing_regexp_dir(Nodes) when is_list(Nodes) -> + %% First find out which modules will be effected. + ?l Mods1=inviso_rt_lib:expand_regexp(".*kernel.*","application.*",[]), + ?l true=(length(Mods1)>1), % Should find more than one module! + ?l Funcs1=lists:foldl(fun(M,Acc)->[{M,M:module_info(exports)}|Acc] end,[],Mods1), + %% Check that these functions are not traced. + io:format("Modules:~w~n",[Mods1]), + ?l {ok,NodeResults}=inviso:tp(Nodes,{".*kernel.*","application.*"},'_','_',[],[]), + io:format("Here 2~w~n",[NodeResults]), + ?l N=lists:foldl(fun({_,L1},A1)->lists:foldl(fun(_,A2)->A2+1 end,A1,L1) end,0,Funcs1), + ?l true=check_noderesults(Nodes,fun({_,{ok,L}})-> N==lists:sum(L) end,NodeResults), + io:format("Here 3~n",[]), + %% Check again! + ?l lists:foreach(fun({M,Funcs})-> + lists:foreach(fun({F,Arity})-> + true=check_on_nodes(Nodes, + erlang, + trace_info, + [{M,F,Arity},traced], + {traced,global}) + end, + Funcs) + end, + Funcs1), + Funcs1. +%% ------------------------------------------------------------------------------ + +deactivate_local_tracing(Nodes) when is_list(Nodes) -> + ?l true=check_on_nodes(Nodes, + erlang, + trace_info, + [{code,which,1},traced], + {traced,local}), + ?l {ok,NodeResults}=inviso:ctpl(Nodes,code,'_','_'), + ?l true=check_noderesults(Nodes,fun({_,{ok,[N]}})when is_integer(N)->true end,NodeResults), + ?l true=check_on_nodes(Nodes, + erlang, + trace_info, + [{code,which,1},traced], + {traced,false}). +%% ------------------------------------------------------------------------------ + +deactivate_global_tracing(Nodes) when is_list(Nodes) -> + ?l true=check_on_nodes(Nodes, + erlang, + trace_info, + [{code,get_path,0},traced], + {traced,global}), + ?l {ok,NodeResults}=inviso:ctp(Nodes,code,'_','_'), + ?l true=check_noderesults(Nodes,fun({_,{ok,[N]}})when is_integer(N)->true end,NodeResults), + ?l true=check_on_nodes(Nodes, + erlang, + trace_info, + [{code,get_path,0},traced], + {traced,false}). +%% ------------------------------------------------------------------------------ + + +%% Function deactivating the functions activated by activate_global_tracing_regexp/1. +deactivate_global_tracing_regexp(Nodes,Funcs1) -> + ?l lists:foreach(fun({M,Funcs})-> + lists:foreach(fun({F,Arity})-> + true=check_on_nodes(Nodes, + erlang, + trace_info, + [{M,F,Arity},traced], + {traced,global}) + end, + Funcs) + end, + Funcs1), + ?l {ok,NodeResults}=inviso:ctp(Nodes,"application.*",'_','_'), + ?l N=lists:foldl(fun({_,L1},A1)->lists:foldl(fun(_,A2)->A2+1 end,A1,L1) end,0,Funcs1), + io:format("Noderesult from deactivate;~w~n",[NodeResults]), + ?l true=check_noderesults(Nodes,fun({_,{ok,L}})-> N==lists:sum(L) end,NodeResults), + ?l lists:foreach(fun({M,Funcs})-> + lists:foreach(fun({F,Arity})-> + true=check_on_nodes(Nodes, + erlang, + trace_info, + [{M,F,Arity},traced], + {traced,false}) + end, + Funcs) + end, + Funcs1). +%% ------------------------------------------------------------------------------ + +%% Function deactivating the functions activated by activate_global_tracing_regexp_dir/1. +deactivate_global_tracing_regexp_dir(Nodes,Funcs1) -> + ?l lists:foreach(fun({M,Funcs})-> + lists:foreach(fun({F,Arity})-> + true=check_on_nodes(Nodes, + erlang, + trace_info, + [{M,F,Arity},traced], + {traced,global}) + end, + Funcs) + end, + Funcs1), + ?l {ok,NodeResults}=inviso:ctp(Nodes,{".*kernel.*","application.*"},'_','_'), + ?l N=lists:foldl(fun({_,L1},A1)->lists:foldl(fun(_,A2)->A2+1 end,A1,L1) end,0,Funcs1), + io:format("Noderesult from deactivate;~w~n",[NodeResults]), + ?l true=check_noderesults(Nodes,fun({_,{ok,L}})-> N==lists:sum(L) end,NodeResults), + ?l lists:foreach(fun({M,Funcs})-> + lists:foreach(fun({F,Arity})-> + true=check_on_nodes(Nodes, + erlang, + trace_info, + [{M,F,Arity},traced], + {traced,false}) + end, + Funcs) + end, + Funcs1). +%% ------------------------------------------------------------------------------ + +%% Help function which starts the inviso_test_proc on all nodes and then sets +%% the call flag on that process. +activate_traceflags(Nodes) -> + ?l lists:foreach(fun(N)->spawn(N,?MODULE,test_proc_init,[]) end,Nodes), + ?l lists:foreach(fun(N)-> + P=rpc:call(N,erlang,whereis,[inviso_test_proc]), + {flags,[]}=rpc:call(N,erlang,trace_info,[P,flags]) + end, + Nodes), + ?l {ok,NodeResults}=inviso:tf(Nodes,inviso_test_proc,[call,timestamp]), + ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults), + ?l lists:foreach(fun(N)-> + P=rpc:call(N,erlang,whereis,[inviso_test_proc]), + {flags,Flags}=rpc:call(N,erlang,trace_info,[P,flags]), + true=lists:member(call,Flags), + true=lists:member(timestamp,Flags) + end, + Nodes), + %% Now try a globally registered process. + ?l [ANode|_]=Nodes, + ?l GPid=spawn(ANode,?MODULE,global_test_proc_init,[]), + ?l ok=poll(global,whereis_name,[global_inviso_test_proc], + fun(P) when is_pid(P)->true;(_)->false end, + 10), + ?l {ok,NodeResults2}= + inviso:tf(Nodes,{global,global_inviso_test_proc},[call,timestamp]), + ?l true=check_noderesults(Nodes, + fun({N,{ok,[1]}}) when N==ANode->true; + ({_,{ok,[0]}})->true; + (_)->false + end, + NodeResults2), + ?l {flags,Flags2}=rpc:call(ANode,erlang,trace_info,[GPid,flags]), + ?l 2=length(Flags2), + ?l true=lists:member(call,Flags2), + ?l true=lists:member(timestamp,Flags2), + true. +%% ------------------------------------------------------------------------------ + +deactivate_traceflags(Nodes) -> + ?l lists:foreach(fun(N)-> + P=rpc:call(N,erlang,whereis,[inviso_test_proc]), + {flags,Flags}=rpc:call(N,erlang,trace_info,[P,flags]), + true=lists:member(call,Flags), + true=lists:member(timestamp,Flags) + end, + Nodes), + ?l {ok,NodeResults}=inviso:ctf(Nodes,inviso_test_proc,[call,timestamp]), + ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults), + ?l lists:foreach(fun(N)-> + P=rpc:call(N,erlang,whereis,[inviso_test_proc]), + {flags,[]}=rpc:call(N,erlang,trace_info,[P,flags]) + end, + Nodes), + ?l GPid=global:whereis_name(global_inviso_test_proc), + ?l ANode=node(GPid), + ?l {flags,Flags2}=rpc:call(ANode,erlang,trace_info,[GPid,flags]), + ?l 2=length(Flags2), + ?l {ok,NodeResults2}=inviso:ctf(Nodes,{global,global_inviso_test_proc},[call,timestamp]), + ?l true=check_noderesults(Nodes, + fun({N,{ok,[1]}}) when N==ANode->true; + ({_,{ok,[0]}})->true; + (_)->false + end, + NodeResults2). +%% ------------------------------------------------------------------------------ + + +activate_meta_tracing(Nodes) -> + ?l {ok,NodeResults1}=inviso:tpm_localnames(), + ?l true=check_noderesults(Nodes,{{ok,1},{ok,1}},NodeResults1), + ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), + {meta,P}=rpc:call(N,erlang,trace_info,[{erlang,register,2},meta]) + end, + Nodes), + ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), + {meta,P}=rpc:call(N,erlang,trace_info,[{erlang,unregister,1},meta]) + end, + Nodes), + ?l {ok,NodeResults2}=inviso:tpm_globalnames(), + ?l true=check_noderesults(Nodes,{{ok,1},{ok,1}},NodeResults2), + ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), + {meta,P}=rpc:call(N, + erlang, + trace_info, + [{global,handle_call,3},meta]) + end, + Nodes), + ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), + {meta,P}=rpc:call(N, + erlang, + trace_info, + [{global,delete_global_name,2},meta]) + end, + Nodes), + + ?l lists:foreach(fun(N)->true=rpc:call(N, + ets, + insert, + [inviso_sideeffect_tab,{tpm_init_func1,0}]), + true=rpc:call(N, + ets, + insert, + [inviso_sideeffect_tab,{tpm_call_func1,0}]), + true=rpc:call(N, + ets, + insert, + [inviso_sideeffect_tab,{tpm_return_func1,0}]) + end, + Nodes), + ?l {ok,NodeResults3}= + inviso:init_tpm(lists, + module_info, + 0, + {?MODULE,tpm_init_func1}, + {?MODULE,tpm_call_func1}, + {?MODULE,tpm_return_func1}, + {?MODULE,tpm_remove_func1}), + ?l true=check_noderesults(Nodes,ok,NodeResults3), + ?l [{_,1}]=ets:lookup(inviso_sideeffect_tab,tpm_init_func1), + ?l {ok,NodeResults3a}= + inviso:init_tpm(lists, + module_info, + 0, + {?MODULE,tpm_init_func1}, + {?MODULE,tpm_call_func1}, + {?MODULE,tpm_return_func1}, + {?MODULE,tpm_remove_func1}), + ?l true=check_noderesults(Nodes,{error,already_initiated},NodeResults3a), +% %% Try more forbidden things. Wildcards not allowed in meta tracing! +% ?l {ok,NodeResults3b}=inviso:tpm(Nodes,lists,'_',0,[{'_',[],[{return_trace}]}]), +% io:format("The noderesults3b is:~w~n",[NodeResults3b]), +% ?l true=check_noderesults(Nodes,{error,bad_mfa},NodeResults3b), + ?l {ok,NodeResults3c}=inviso:tpm(Nodes,lists,module_info,0,[{'_',[],[{return_trace}]}]), + ?l true=check_noderesults(Nodes,{ok,1},NodeResults3c), + ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), + {meta,P}=rpc:call(N,erlang,trace_info,[{lists,module_info,0},meta]) + end, + Nodes), + ?l lists:foreach(fun(N)->rpc:call(N,lists,module_info,[]) end,Nodes), + ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_call_func1],[{tpm_call_func1,1}],20), + ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_return_func1],[{tpm_return_func1,1}],20), + ?l lists:foreach(fun(N)->rpc:call(N,lists,module_info,[]) end,Nodes), + ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_call_func1],[{tpm_call_func1,2}],20), + ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_return_func1],[{tpm_return_func1,2}],20), + + ?l {ok,NodeResults4}= + inviso:init_tpm(math, + module_info, + 1, + {?MODULE,tpm_init_func2}, % Does not exist on purpose. + {?MODULE,tpm_call_func2}, % Does not exist on purpose. + {?MODULE,tpm_return_func2}, % Does not exist on purpose. + {?MODULE,tpm_remove_func2}), % Does not exist on purpose. + ?l true=check_noderesults(Nodes,ok,NodeResults4), + ?l {ok,NodeResults5}= + inviso:tpm_ms(math,module_info,1,ms1,[{'_',[],[{return_trace}]}]), + ?l true=check_noderesults(Nodes,{ok,1},NodeResults5), + ?l lists:foreach(fun(N)->{meta_match_spec,[{'_',[],[{return_trace}]}]}= + rpc:call(N,erlang,trace_info,[{math,module_info,1}, + meta_match_spec]) + end, + Nodes), + + ?l {ok,NodeResults6}=inviso:tpm_ms(math,module_info,1,ms2,[{[exports],[],[]}]), + ?l true=check_noderesults(Nodes,{ok,1},NodeResults6), + ?l lists:foreach(fun(N)->{meta_match_spec,[{[exports],[],[]},{'_',[],[{return_trace}]}]}= + rpc:call(N,erlang,trace_info,[{math,module_info,1}, + meta_match_spec]) + end, + Nodes), + ?l {ok,NodeResults7}=inviso:tpm_ms(math,module_info,1,ms3,[{[attributes],[],[]}]), + ?l true=check_noderesults(Nodes,{ok,1},NodeResults7), + ?l lists:foreach(fun(N)->{meta_match_spec,[{[attributes],[],[]}, + {[exports],[],[]}, + {'_',[],[{return_trace}]}]}= + rpc:call(N,erlang,trace_info,[{math,module_info,1}, + meta_match_spec]) + end, + Nodes), + ?l {ok,NodeResults8}=inviso:ctpm_ms(math,module_info,1,ms2), + ?l true=check_noderesults(Nodes,ok,NodeResults8), + ?l lists:foreach(fun(N)->{meta_match_spec,[{[attributes],[],[]}, + {'_',[],[{return_trace}]}]}= + rpc:call(N,erlang,trace_info,[{math,module_info,1}, + meta_match_spec]) + end, + Nodes), + ?l io:format("whereis:~w~n",[lists:map(fun(N)->rpc:call(N,erlang,whereis,[inviso_rt_meta]) end,Nodes)]), + ?l {ok,NodeResults8}=inviso:ctpm_ms(math,module_info,1,ms3), + ?l io:format("whereis:~w~n",[lists:map(fun(N)->rpc:call(N,erlang,whereis,[inviso_rt_meta]) end,Nodes)]), + ?l {ok,NodeResults8}=inviso:ctpm_ms(math,module_info,1,ms1), + ?l lists:foreach(fun(N)->{meta_match_spec,false}= + rpc:call(N,erlang,trace_info,[{math,module_info,1}, + meta_match_spec]) + end, + Nodes), + + %% Now try to do this with exception tracing instead. + %% Reset the side effect tables. + ?l lists:foreach(fun(N)->true=rpc:call(N, + ets, + insert, + [inviso_sideeffect_tab,{tpm_init_func1,0}]), + true=rpc:call(N, + ets, + insert, + [inviso_sideeffect_tab,{tpm_call_func1,0}]), + true=rpc:call(N, + ets, + insert, + [inviso_sideeffect_tab,{tpm_return_func1,0}]) + end, + Nodes), + ?l {ok,NodeResults9}= + inviso:init_tpm(?MODULE, + failing_function, + 1, + {?MODULE,tpm_init_func1}, + {?MODULE,tpm_call_func1}, + {?MODULE,tpm_return_func1}, + {?MODULE,tpm_remove_func1}), + ?l true=check_noderesults(Nodes,ok,NodeResults9), + ?l [{_,1}]=ets:lookup(inviso_sideeffect_tab,tpm_init_func1), + ?l {ok,NodeResults10}=inviso:tpm(Nodes,?MODULE,failing_function,1,[{'_',[],[{exception_trace}]}]), + ?l true=check_noderesults(Nodes,{ok,1},NodeResults10), + ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), + {meta,P}=rpc:call(N,erlang,trace_info,[{?MODULE,failing_function,1},meta]) + end, + Nodes), + ?l lists:foreach(fun(N)->rpc:call(N,?MODULE,failing_function,[nofailure]) end,Nodes), + ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_call_func1],[{tpm_call_func1,1}],20), + ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_return_func1],[{tpm_return_func1,1}],20), + ?l lists:foreach(fun(N)->rpc:call(N,?MODULE,failing_function,[failure]) end,Nodes), + ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_call_func1],[{tpm_call_func1,2}],20), + ?l ok=poll(ets,lookup,[inviso_sideeffect_tab,tpm_return_func1],[{tpm_return_func1,3}],20), + + ok. +%% ------------------------------------------------------------------------------ + +%% This function is for testing that appending the tracer to a trace action term +%% works. +activate_deactivate_meta_tracing_tracer(Nodes) -> + ?l {ok,NodeResults}= + inviso:tpm_tracer(Nodes,lists,module_info,0,[{'_',[],[{trace,[all],[call]}]}],void), + ?l true=check_noderesults(Nodes,{ok,1},NodeResults), + ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), + {meta,P}=rpc:call(N,erlang,trace_info,[{lists,module_info,0},meta]), + {meta_match_spec,[{'_',[],[{trace,[all],Enable}]}]}= + rpc:call(N,erlang,trace_info,[{lists,module_info,0}, + meta_match_spec]), + true=list_search(Enable,fun({{tracer,P}}) when is_port(P)->true; + (_) -> false + end) + end, + Nodes), + ?l {ok,NodeResults2}= + inviso:ctpm(Nodes,lists,module_info,0), + ?l true=check_noderesults(Nodes,ok,NodeResults2), + ?l lists:foreach(fun(N)->{meta,false}= + rpc:call(N,erlang,trace_info,[{lists,module_info,0},meta]) + end, + Nodes), + ok. +%% ------------------------------------------------------------------------------ + +deactivate_meta_tracing(Nodes) -> + ?l lists:foreach(fun(N)->{meta,P}= + rpc:call(N,erlang,trace_info,[{erlang,register,2},meta]), + true=is_pid(P) + end, + Nodes), + ?l lists:foreach(fun(N)->{meta,P}= + rpc:call(N,erlang,trace_info,[{erlang,unregister,1},meta]), + true=is_pid(P) + end, + Nodes), + ?l {ok,NodeResults1}=inviso:ctpm_localnames(), + ?l lists:foreach(fun(N)->{meta,false}= + rpc:call(N,erlang,trace_info,[{erlang,register,2},meta]) end, + Nodes), + ?l lists:foreach(fun(N)->{meta,false}= + rpc:call(N,erlang,trace_info,[{erlang,unregister,1},meta]) + end, + Nodes), + ?l true=check_noderesults(Nodes,{ok,ok},NodeResults1), + + ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), + {meta,P}=rpc:call(N, + erlang, + trace_info, + [{global,handle_call,3},meta]) + end, + Nodes), + ?l lists:foreach(fun(N)->P=rpc:call(N,erlang,whereis,[inviso_rt_meta]), + {meta,P}=rpc:call(N, + erlang, + trace_info, + [{global,delete_global_name,2},meta]) + end, + Nodes), + ?l {ok,NodeResults1b}=inviso:ctpm_globalnames(), + ?l true=check_noderesults(Nodes,{ok,ok},NodeResults1b), + ?l lists:foreach(fun(N)-> + {meta,false}=rpc:call(N, + erlang, + trace_info, + [{global,handle_call,3},meta]) + end, + Nodes), + ?l lists:foreach(fun(N)-> + {meta,false}=rpc:call(N, + erlang, + trace_info, + [{global,delete_global_name,2},meta]) + end, + Nodes), + + ?l lists:foreach(fun(N)->{meta,P}= + rpc:call(N,erlang,trace_info,[{lists,module_info,0},meta]), + true=is_pid(P) + end, + Nodes), + ?l {ok,NodeResults2}=inviso:ctpm(lists,module_info,0), + ?l true=check_noderesults(Nodes,ok,NodeResults2), + ?l lists:foreach(fun(N)->{meta,false}= + rpc:call(N,erlang,trace_info,[{lists,module_info,0},meta]) end, + Nodes), + ?l [{_,0}]=ets:lookup(inviso_sideeffect_tab,tpm_init_func1), + ?l {ok,NodeResults3}=inviso:ctpm(math,module_info,1), + ?l true=check_noderesults(Nodes,ok,NodeResults3), + ok. +%% ------------------------------------------------------------------------------ + +%% Functions acting as callbacks for testing the meta tracing mechanisms. +tpm_init_func1(_M,_F,_Arity,PublLD) -> + ets:update_counter(inviso_sideeffect_tab,tpm_init_func1,1), + {ok,PublLD,void}. +tpm_call_func1(_Pid,{call,_Args,_TS},PublLD) -> + ets:update_counter(inviso_sideeffect_tab,tpm_call_func1,1), + {ok,PublLD,void}. +tpm_return_func1(_Pid,{return_from,_ReturnVal,_TS},PublLD) -> + ets:update_counter(inviso_sideeffect_tab,tpm_return_func1,1), + {ok,PublLD,void}; +tpm_return_func1(_Pid,{exception_from,_ReturnVal,_TS},PublLD) -> + ets:update_counter(inviso_sideeffect_tab,tpm_return_func1,1), + ets:update_counter(inviso_sideeffect_tab,tpm_return_func1,1), + {ok,PublLD,void}. +tpm_remove_func1(_M,_F,_Arity,PublLD) -> + ets:update_counter(inviso_sideeffect_tab,tpm_init_func1,-1), + {ok,PublLD}. +%% ------------------------------------------------------------------------------ + + +%% Help function which traces on a function and makes function calls until there +%% are two files in the wrap-set. +fill_and_reach_two_wrapfiles(PrivDir,RegExp,Nodes) -> + ?l lists:foreach(fun(N)->spawn(N,?MODULE,test_proc_init,[]) end,Nodes), + ?l {ok,NodeResults1}=inviso:tpl(Nodes,?MODULE,test_function,0,[]), + ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults1), + ?l {ok,NodeResults2}=inviso:tf(Nodes,inviso_test_proc,[call]), + ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults2), + fill_and_reach_two_wrapfiles_2(PrivDir,RegExp,Nodes), + ?l {ok,NodeResults3}=inviso:ctf(Nodes,inviso_test_proc,[call]), + ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults3), + ?l {ok,NodeResults4}=inviso:ctpl(Nodes,?MODULE,test_function,0), + ?l true=check_noderesults(Nodes,{ok,[1]},NodeResults4), + ok. + +fill_and_reach_two_wrapfiles_2(PrivDir,RegExp,[Node|Rest]) -> + ?l ok=rpc:call(Node,?MODULE,fill_and_reach_two_wrapfiles_3,[PrivDir,RegExp]), + fill_and_reach_two_wrapfiles_2(PrivDir,RegExp,Rest); +fill_and_reach_two_wrapfiles_2(_,_,[]) -> + ok. + +fill_and_reach_two_wrapfiles_3(Dir,RegExp) -> + ok=send_to_test_proc({apply,?MODULE,test_function,[]}, + fun reach_two_wraps_stopfun/1, + {Dir,RegExp++atom_to_list(node())}, + 100). + +%% Help function intended to be used as fun in a send_to_test_proc/4 call. +%% The function lists the content of Dir and looks for occurancies of String. +%% If two files containing the string String are found, 'done' is returned. +%% Otherwise 'continue'. +reach_two_wraps_stopfun({Dir,RegExp}) -> + case file:list_dir(Dir) of + {ok,FileNames} -> + case how_many_files_regexp(FileNames,RegExp,0) of + {ok,2} -> + done; + _ -> + continue + end; + {error,_Reason} -> + error + end. +%% ------------------------------------------------------------------------------ + +%% ------------------------------------------------------------------------------ +%% Help function for the overload tests. These functions are used as callbacks. +%% ------------------------------------------------------------------------------ + +overload1(_) -> + ets:update_counter(inviso_sideeffect_tab,ovl1,1), + ok. +%% This function is used when timeout occurs inside the runtime component. +%% That is it is time to check for overload. +overload2({timeout,overload2i_data}) -> + ets:update_counter(inviso_sideeffect_tab,ovl2,1), + ok. +overload2i() -> + ets:insert(inviso_sideeffect_tab,{ovl2,0}), + {ok,overload2i_data}. +overload2r(overload2i_data) -> + ets:delete(inviso_sideeffect_tab,ovl2). + +%% This function is used when timeout occurs inside the runtime component. +%% That is it is time to check for overload. +overload3({timeout,overload3i_data}) -> + ets:update_counter(inviso_sideeffect_tab,ovl3,1), + ok; +overload3(_) -> % Must handle garbage too. + ignore. +overload3i() -> + ets:insert(inviso_sideeffect_tab,{ovl3,0}), + {ok,overload3i_data}. +overload3r(overload3i_data) -> + ets:insert(inviso_sideeffect_tab,{ovl3r,done}), + ets:delete(inviso_sideeffect_tab,ovl3). + +overload4(_) -> + case ets:lookup(inviso_sideeffect_tab,ovl4_suspend) of + [] -> % We are supposed to be running. + ets:update_counter(inviso_sideeffect_tab,ovl4,1), + ok; + [_] -> + {suspend,test} + end. + +%% This function is used when overload check is done by icomming message. +overload5({msg,{test_of_loadcheck,overload5i_data}}) -> + ets:update_counter(inviso_sideeffect_tab,ovl5,1), + ok; +overload5(_) -> + ignore. +overload5i() -> + ets:insert(inviso_sideeffect_tab,{ovl5,0}), + {ok,overload5i_data}. +overload5r(overload5i_data) -> + ets:delete(inviso_sideeffect_tab,ovl5), + ets:insert(inviso_sideeffect_tab,{ovl5r,done}); +overload5r(X) -> + erlang:display({'***',overload5r,X}). + +overload6(_) -> + ets:update_counter(inviso_sideeffect_tab,ovl6,1), + ok. +%% ------------------------------------------------------------------------------ + +%% ------------------------------------------------------------------------------ +%% Help function for the subscription tests. These function implements a collector +%% process which will subscribe to inviso_events from the control component. +%% ------------------------------------------------------------------------------ + +%% Function which can be used to check if an inviso_event has arrived. The function +%% takes a fun which tests the messages. +check_msg_collector([],_,_) -> + true; +check_msg_collector(_,_,0) -> + false; +check_msg_collector(Nodes,Fun,T) -> + Ref=make_ref(), + inviso_collector_proc ! {fetch_message,self(),Ref,Fun}, + receive + {inviso,Ref,{true,Node}} -> + check_msg_collector(lists:delete(Node,Nodes),Fun,T-1); + {inviso,Ref,false} -> + timer:sleep(100), + check_msg_collector(Nodes,Fun,T-1) + end. + +%% Spawn on this function to get a subscriber. +inviso_msg_collector() -> + register(inviso_collector_proc,self()), + inviso_msg_collector_loop([]). + +inviso_msg_collector_loop(Msgs) -> + receive + {fetch_message,From,Ref,Fun} -> + {NewMsgs,Reply}=inviso_msg_collector_selector(Msgs,Fun,[]), + From ! {inviso,Ref,Reply}, + inviso_msg_collector_loop(NewMsgs); + Msg -> + inviso_msg_collector_loop([Msg|Msgs]) + end. + +inviso_msg_collector_selector([M|Rest],Fun,Accum) -> + case Fun(M) of + {true,X} -> + {Rest++Accum,{true,X}}; + _ -> + inviso_msg_collector_selector(Rest,Fun,[M|Accum]) + end; +inviso_msg_collector_selector([],_,Accum) -> + {Accum,false}. +%% ------------------------------------------------------------------------------ + + +%% ============================================================================== +%% Help functions +%% ============================================================================== + +list_search([E|Rest],Fun) -> + case Fun(E) of + true -> + true; + false -> + list_search(Rest,Fun) + end; +list_search([],_Fun) -> + false. +%% ------------------------------------------------------------------------------ + +%% Help function checking that there is a Result for each node in Nodes. +%% Returns 'true' if successful. +check_noderesults(Nodes,Fun,[{Node,Result}|Rest]) when is_function(Fun) -> + case Fun({Node,Result}) of + true -> + case lists:member(Node,Nodes) of + true -> + check_noderesults(lists:delete(Node,Nodes),Fun,Rest); + false -> % Not good. + unknown_node_in_returnvalue + end; + _ -> + illegal_result + end; +check_noderesults(Nodes,Result,[{Node,Result}|Rest]) -> + case lists:member(Node,Nodes) of + true -> + check_noderesults(lists:delete(Node,Nodes),Result,Rest); + false -> % Not good. + unknown_node_in_returnvalue + end; +check_noderesults([],_,[]) -> + true; +check_noderesults(X,Y,Z) -> + io:format("Bad arguments to check noderesults:~w~n~w~n~w~n",[X,Y,Z]), + false. +%% ------------------------------------------------------------------------------ + +%% Help function doing rpc on all nodes in Nodes calling M:F. Returns 'true' if +%% successful. +check_on_nodes([Node|Rest],M,F,Args,Result) when Node==node() -> + if + is_function(Result) -> + ?l true=Result(apply(M,F,Args)); + true -> + ?l Result=apply(M,F,Args) + end, + check_on_nodes(Rest,M,F,Args,Result); +check_on_nodes([Node|Rest],M,F,Args,Result) -> + if + is_function(Result) -> + ?l true=Result(rpc:call(Node,M,F,Args)); + true -> + ?l Result=rpc:call(Node,M,F,Args) + end, + check_on_nodes(Rest,M,F,Args,Result); +check_on_nodes([],_,_,_,_) -> + true. +%% ------------------------------------------------------------------------------ + +%% Help function which given a list of files searches through it and returns +%% how many satisfies the RegExp. +%% Returns {ok,N}. +how_many_files_regexp([],_,N) -> + {ok,N}; +how_many_files_regexp([FName|Rest],RegExp,N) -> + case regexp:first_match(FName,RegExp) of + {match,1,_} -> + how_many_files_regexp(Rest,RegExp,N+1); + nomatch -> + how_many_files_regexp(Rest,RegExp,N); + {error,Reason} -> + test_server:fail(Reason) + end. +%% ------------------------------------------------------------------------------ + +%% Help function killing a bunch of registered processes. +process_killer([RegName|Rest]) -> + case whereis(RegName) of + undefined -> + case global:whereis_name(RegName) of + undefined -> + process_killer(Rest); + P when is_pid(P) -> + if + node()==node(P) -> + exit(P,kill); + true -> + true + end, + process_killer(Rest) + end; + P when is_pid(P) -> + exit(P,kill), + process_killer(Rest) + end; +process_killer([]) -> + true. +%% ------------------------------------------------------------------------------ + +%% Help function which waits for a function call to become Result. This is useful +%% if what we are waiting for can happend independantly of indications we have +%% access to. +poll(_,_,_,_,0) -> + error; +poll(M,F,Args,Result,Times) -> + try apply(M,F,Args) of + What when is_function(Result) -> + case Result(What) of + true -> + ok; + _ -> + timer:sleep(100), + poll(M,F,Args,Result,Times-1) + end; + Result -> + ok; + _ -> + timer:sleep(100), + poll(M,F,Args,Result,Times-1) + catch + error:Reason -> + io:format("Apply in suite-function poll/5 failed, ~w~n",[Reason]), + timer:sleep(100), + poll(M,F,Args,Result,Times-1) + end. +%% ------------------------------------------------------------------------------ + +insert_remotenode_config(Name,Node,Config) -> + [{remotenode,{Name,Node}}|Config]. +%% ------------------------------------------------------------------------------ + +insert_timetraphandle_config(Handle,Config) -> + [{timetraphandle,Handle}|Config]. +%% ------------------------------------------------------------------------------ + +get_remotenode_config(Name, [{remotenode, {Name, Node}}| _Cs]) -> + Node; +get_remotenode_config(Name, [_ | Cs]) -> + get_remotenode_config(Name, Cs); +get_remotenode_config(Name, []) -> + exit({no_remotenode, Name}). + +%% ------------------------------------------------------------------------------ + +get_timetraphandle_config(Config) -> + {value,{_,Handle}}=lists:keysearch(timetraphandle,1,Config), + Handle. +%% ------------------------------------------------------------------------------ + +get_remotenodes_config([{remotenode,{_Name,Node}}|Config]) -> + [Node|get_remotenodes_config(Config)]; +get_remotenodes_config([_|Config]) -> + get_remotenodes_config(Config); +get_remotenodes_config([]) -> + []. +%% ------------------------------------------------------------------------------ + +remove_remotenode_config(Name, [{remotenode, {Name, _}} | Cs]) -> + Cs; +remove_remotenode_config(Name, [C | Cs]) -> + [C | remove_remotenode_config(Name, Cs)]; +remove_remotenode_config(_Name, []) -> + []. + +%% ------------------------------------------------------------------------------ + +remove_timetraphandle_config(Config) -> + lists:keydelete(timetraphandle,1,Config). +%% ------------------------------------------------------------------------------ + +%% This function can be meta traced in order to check that exception_trace works. +%% Must be exported. +failing_function(nofailure) -> + true; +failing_function(failure) -> + exit(failure). +%% ------------------------------------------------------------------------------ + +%% ============================================================================== +%% Code for a test process which can be started. +%% ============================================================================== + +test_proc_init() -> + register(inviso_test_proc,self()), + test_proc_loop(). + +test_proc_loop() -> + receive + {apply,M,F,Args} -> + apply(M,F,Args), + test_proc_loop(); + X -> + io:format("Got ~w~n",[X]), + test_proc_loop() + end. + +global_test_proc_init() -> + global:register_name(global_inviso_test_proc,self()), + test_proc_loop(). +%% ------------------------------------------------------------------------------ + +send_to_test_proc(_,_,_,0) -> + error; +send_to_test_proc(Msg,Fun,FunArg,N) -> + inviso_test_proc ! Msg, + case Fun(FunArg) of + done -> + ok; + error -> + test_server:fail(send_to_test_proc); + _ -> + send_to_test_proc(Msg,Fun,FunArg,N-1) + end. +%% ------------------------------------------------------------------------------ + + +%% This function is here to be traced on by the inviso_test_proc. Must be exported. +test_function() -> + 1+1. +%% ------------------------------------------------------------------------------ + + +%% ============================================================================== +%% Code for a test side effect table process. +%% ============================================================================== + +%% The side effect logger is a process owning a public ETS table. The idea is that +%% various callback functions can write in the table when called. In that way +%% correct calling of the call-backs can be verified. +start_side_effect_logger(Node) -> + ?l true=is_pid(spawn(Node,?MODULE,side_effect_logger_proc,[])), + ?l ok=poll(rpc,call,[Node,ets,lookup,[inviso_sideeffect_tab,foo]],[],20). + +%% This one must be exported. +side_effect_logger_proc() -> + register(inviso_tab_proc,self()), % So we can kill it later. + ets:new(inviso_sideeffect_tab,[public,named_table]), + side_effect_logger_proc_2(). + +side_effect_logger_proc_2() -> + receive + _X -> % This process is not expecting anything! + side_effect_logger_proc_2() + end. +%% ------------------------------------------------------------------------------ diff --git a/lib/runtime_tools/test/inviso_testmodule1_foo.erl b/lib/runtime_tools/test/inviso_testmodule1_foo.erl new file mode 100644 index 0000000000..a7a22cad39 --- /dev/null +++ b/lib/runtime_tools/test/inviso_testmodule1_foo.erl @@ -0,0 +1,9 @@ +-module(inviso_testmodule1_foo). + +-compile(export_all). + +%% The purpose of this module is simply to have a module that is +%% guaranteed not loaded. + +foo() -> + true. diff --git a/lib/runtime_tools/test/runtime_tools.cover b/lib/runtime_tools/test/runtime_tools.cover new file mode 100644 index 0000000000..2d62ebe6ac --- /dev/null +++ b/lib/runtime_tools/test/runtime_tools.cover @@ -0,0 +1 @@ +{exclude,[observer_backend]}. diff --git a/lib/runtime_tools/test/runtime_tools.spec b/lib/runtime_tools/test/runtime_tools.spec new file mode 100644 index 0000000000..a60a533ce2 --- /dev/null +++ b/lib/runtime_tools/test/runtime_tools.spec @@ -0,0 +1 @@ +{topcase, {dir, "../runtime_tools_test"}}. diff --git a/lib/runtime_tools/test/runtime_tools_SUITE.erl b/lib/runtime_tools/test/runtime_tools_SUITE.erl new file mode 100644 index 0000000000..84e255e126 --- /dev/null +++ b/lib/runtime_tools/test/runtime_tools_SUITE.erl @@ -0,0 +1,50 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(runtime_tools_SUITE). +-include("test_server.hrl"). + +%% Test server specific exports +-export([all/1]). +-export([init_per_testcase/2, end_per_testcase/2]). + +%% Test cases +-export([app_file/1]). + +%% Default timetrap timeout (set in init_per_testcase) +-define(default_timeout, ?t:minutes(1)). + +init_per_testcase(_Case, Config) -> + Dog = test_server:timetrap(?default_timeout), + [{watchdog, Dog} | Config]. + +end_per_testcase(_Case, Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +all(suite) -> + [app_file]. + +app_file(suite) -> + []; +app_file(doc) -> + ["Testing .app file"]; +app_file(Config) when is_list(Config) -> + ?line ok = ?t:app_test(runtime_tools), + ok. diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl index e3b6ffa125..cb78acb84c 100644 --- a/lib/ssh/src/ssh_cli.erl +++ b/lib/ssh/src/ssh_cli.erl @@ -415,14 +415,12 @@ start_shell(ConnectionManager, State) -> Shell = State#state.shell, ShellFun = case is_function(Shell) of true -> + {ok, User} = + ssh_userreg:lookup_user(ConnectionManager), case erlang:fun_info(Shell, arity) of {arity, 1} -> - {ok, User} = - ssh_userreg:lookup_user(ConnectionManager), fun() -> Shell(User) end; {arity, 2} -> - {ok, User} = - ssh_userreg:lookup_user(ConnectionManager), {ok, PeerAddr} = ssh_connection_manager:peer_addr(ConnectionManager), fun() -> Shell(User, PeerAddr) end; @@ -437,10 +435,28 @@ start_shell(ConnectionManager, State) -> State#state{group = Group, buf = empty_buf()}. start_shell(_ConnectionManager, Cmd, #state{exec={M, F, A}} = State) -> - Group = group:start(self(), {M, F, A++[Cmd]}, [{echo,false}]), + Group = group:start(self(), {M, F, A++[Cmd]}, [{echo, false}]), + State#state{group = Group, buf = empty_buf()}; +start_shell(ConnectionManager, Cmd, #state{exec=Shell} = State) when is_function(Shell) -> + {ok, User} = + ssh_userreg:lookup_user(ConnectionManager), + ShellFun = + case erlang:fun_info(Shell, arity) of + {arity, 1} -> + fun() -> Shell(Cmd) end; + {arity, 2} -> + fun() -> Shell(Cmd, User) end; + {arity, 3} -> + {ok, PeerAddr} = + ssh_connection_manager:peer_addr(ConnectionManager), + fun() -> Shell(Cmd, User, PeerAddr) end; + _ -> + Shell + end, + Echo = get_echo(State#state.pty), + Group = group:start(self(), ShellFun, [{echo,Echo}]), State#state{group = Group, buf = empty_buf()}. - % Pty can be undefined if the client never sets any pty options before % starting the shell. get_echo(undefined) -> diff --git a/lib/ssh/src/ssh_connection_controler.erl b/lib/ssh/src/ssh_connection_controler.erl index 636ecba532..ca3e62dc83 100644 --- a/lib/ssh/src/ssh_connection_controler.erl +++ b/lib/ssh/src/ssh_connection_controler.erl @@ -126,8 +126,8 @@ handle_cast(_, State) -> %% handle_info(ssh_connected, State) -> %% {stop, normal, State}; %% Servant termination. -handle_info({'EXIT', _Pid, normal}, State) -> - {stop, normal, State}. +handle_info({'EXIT', _Pid, Reason}, State) -> + {stop, Reason, State}. %%----------------------------------------------------------------- %% Func: code_change/3 diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl index 9e55312e5f..6bf89224cf 100644 --- a/lib/ssh/src/ssh_connection_manager.erl +++ b/lib/ssh/src/ssh_connection_manager.erl @@ -560,13 +560,18 @@ handle_info({'EXIT', _, _}, State) -> %% The return value is ignored. %%-------------------------------------------------------------------- terminate(Reason, #state{connection_state = - #connection{requests = Requests}, + #connection{requests = Requests, + sub_system_supervisor = SubSysSup}, opts = Opts}) -> SSHOpts = proplists:get_value(ssh_opts, Opts), disconnect_fun(Reason, SSHOpts), (catch lists:foreach(fun({_, From}) -> gen_server:reply(From, {error, connection_closed}) end, Requests)), + Address = proplists:get_value(address, Opts), + Port = proplists:get_value(port, Opts), + SystemSup = ssh_system_sup:system_supervisor(Address, Port), + ssh_system_sup:stop_subsystem(SystemSup, SubSysSup), ok. %%-------------------------------------------------------------------- diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl index 40db2e4adf..f4570b8a48 100644 --- a/lib/ssh/src/ssh_system_sup.erl +++ b/lib/ssh/src/ssh_system_sup.erl @@ -33,7 +33,8 @@ stop_system/2, system_supervisor/2, subsystem_supervisor/1, channel_supervisor/1, connection_supervisor/1, - acceptor_supervisor/1, start_subsystem/2, restart_subsystem/2, restart_acceptor/2]). + acceptor_supervisor/1, start_subsystem/2, restart_subsystem/2, + restart_acceptor/2, stop_subsystem/2]). %% Supervisor callback -export([init/1]). @@ -83,6 +84,23 @@ start_subsystem(SystemSup, Options) -> Spec = ssh_subsystem_child_spec(Options), supervisor:start_child(SystemSup, Spec). +stop_subsystem(SystemSup, SubSys) -> + case lists:keyfind(SubSys, 2, supervisor:which_children(SystemSup)) of + false -> + {error, not_found}; + {Id, _, _, _} -> + spawn(fun() -> supervisor:terminate_child(SystemSup, Id), + supervisor:delete_child(SystemSup, Id) end), + ok; + {'EXIT', {noproc, _}} -> + %% Already terminated; probably shutting down. + ok; + {'EXIT', {shutdown, _}} -> + %% Already shutting down. + ok + end. + + restart_subsystem(Address, Port) -> SysSupName = make_name(Address, Port), SubSysName = id(ssh_subsystem_sup, Address, Port), diff --git a/lib/ssl/Makefile b/lib/ssl/Makefile index 8c9d78d4bc..daad7dc3e6 100644 --- a/lib/ssl/Makefile +++ b/lib/ssl/Makefile @@ -25,11 +25,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # Macros # -SUB_DIRECTORIES = src c_src doc/src - -ifeq ($(CROSS_COMPILING),no) -SUB_DIRECTORIES += examples/certs examples/src -endif +SUB_DIRECTORIES = src c_src doc/src examples/certs examples/src include vsn.mk VSN = $(SSL_VSN) diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index def61bcf03..0f3054aec3 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> @@ -69,10 +69,13 @@ </p> <p> <c>ssloption() = {verify, verify_type()} | + {verify_fun, {fun(), term()}} | {fail_if_no_peer_cert, boolean()} {depth, integer()} | - {certfile, path()} | {keyfile, path()} | {password, string()} | - {cacertfile, path()} | {dhfile, path()} | {ciphers, ciphers()} | + {cert, der_bin()}| {certfile, path()} | + {key, der_bin()} | {keyfile, path()} | {password, string()} | + {cacerts, [der_bin()]} | {cacertfile, path()} | + |{dh, der_bin()} | {dhfile, path()} | {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()} </c></p> @@ -91,6 +94,8 @@ <p><c>verify_type() = verify_none | verify_peer</c></p> <p><c>path() = string() - representing a file path.</c></p> + + <p><c>der_bin() = binary() -Asn1 DER encoded entity as an erlang binary.</c></p> <p><c>host() = hostname() | ipaddress()</c></p> @@ -121,115 +126,52 @@ <p><c>ssl_imp() = new | old - default is new.</c></p> </section> - -<section> - <title>SSL OPTION DESCRIPTIONS</title> + + <section> + <title>SSL OPTION DESCRIPTIONS - COMMON for SERVER and CLIENT</title> + + <p>Options described here are options that are have the same + meaning in the client and the server. + </p> <taglist> - <tag>{verify, verify_type()}</tag> - <item> If <c>verify_none</c> is specified x509-certificate - path validation errors at the client side - will not automatically cause the connection to fail, as - it will if the verify type is <c>verify_peer</c>. See also - the option verify_fun. - Servers only do the path validation if <c>verify_peer</c> is set to - true, as it then will - send a certificate request to - the client (this message is not sent if the verify option is - <c>verify_none</c>) and you may then also want to specify - the option <c>fail_if_no_peer_cert</c>. - </item> - <tag>{fail_if_no_peer_cert, boolean()}</tag> - <item>Used together with {verify, verify_peer} by a ssl server. - If set to true, - the server will fail if the client does not have a certificate - to send, e.i sends a empty certificate, if set to false it will - only fail if the client sends a invalid certificate (an empty - certificate is considered valid). - </item> + <tag>{cert, der_bin()}</tag> + <item> The DER encoded users certificate. If this option + is supplied it will override the certfile option.</item> - <tag>{verify_fun, fun(ErrorList) -> boolean()}</tag> - <item>Used by the ssl client to determine if - x509-certificate path validations errors are acceptable or - if the connection should fail. Defaults to: - -<code> -fun(ErrorList) -> - case lists:foldl(fun({bad_cert,unknown_ca}, Acc) -> - Acc; - (Other, Acc) -> - [Other | Acc] - end, [], ErrorList) of - [] -> - true; - [_|_] -> - false - end -end -</code> - I.e. by default if the only error found was that the CA-certificate - holder was unknown this will be accepted. - - Possible errors in the error list are: - {bad_cert, cert_expired}, {bad_cert, invalid_issuer}, - {bad_cert, invalid_signature}, {bad_cert, name_not_permitted}, - {bad_cert, unknown_ca}, - {bad_cert, cert_expired}, {bad_cert, invalid_issuer}, - {bad_cert, invalid_signature}, {bad_cert, name_not_permitted}, - {bad_cert, cert_revoked} (not implemented yet), - {bad_cert, unknown_critical_extension} or {bad_cert, term()} - </item> - + <tag>{certfile, path()}</tag> + <item>Path to a file containing the user's certificate.</item> - <tag>{validate_extensions_fun, fun()}</tag> - <item> - This options makes it possible to supply a fun to validate - possible application specific certificate extensions - during the certificat path validation. This option - will be better documented onec the public_key API is more - mature. - </item> + <tag>{key, der_bin()}</tag> + <item> The DER encoded users private key. If this option + is supplied it will override the keyfile option.</item> - <tag>{depth, integer()}</tag> - <item>Specifies the maximum - verification depth, i.e. how far in a chain of certificates the - verification process can proceed before the verification is - considered to fail. Peer certificate = 0, CA certificate = 1, - higher level CA certificate = 2, etc. The value 2 thus means - that a chain can at most contain peer cert, CA cert, next CA - cert, and an additional CA cert. The default value is 1. - </item> - - <tag>{certfile, path()}</tag> - <item>Path to a file containing the - user's certificate. Optional for clients but note - that some servers requires that the client can certify - itself. </item> <tag>{keyfile, path()}</tag> <item>Path to file containing user's private PEM encoded key. As PEM-files may contain several entries this option defaults to the same file as given by certfile option.</item> + <tag>{password, string()}</tag> <item>String containing the user's password. Only used if the private keyfile is password protected. </item> + + <tag>{cacerts, [der_bin()]}</tag> + <item> The DER encoded trusted certificates. If this option + is supplied it will override the cacertfile option.</item> + <tag>{cacertfile, path()}</tag> <item>Path to file containing PEM encoded CA certificates (trusted certificates used for verifying a peer certificate). May be omitted if you do not want to verify the peer.</item> - <tag>{dhfile, path()}</tag> - <item>Path to file containing PEM encoded Diffie Hellman parameters, - for the server to use if a cipher suite using Diffie Hellman key exchange - is negotiated. If not specified hardcode parameters will be used. - </item> - <tag>{ciphers, ciphers()}</tag> - <item>The function <c>ciphers_suites/0</c> can - be used to find all available ciphers. + <item>The cipher suites that should be supported. The function + <c>ciphers_suites/0</c> can be used to find all available + ciphers. </item> <tag>{ssl_imp, ssl_imp()}</tag> @@ -237,13 +179,152 @@ end new. </item> + <tag>{secure_renegotiate, boolean()}</tag> + <item>Specifies if to reject renegotiation attempt that does + not live up to RFC 5746. By default secure_renegotiate is + set to false i.e. secure renegotiation will be used if possible + but it will fallback to unsecure renegotiation if the peer + does not support RFC 5746. + </item> + + <tag>{depth, integer()}</tag> + <item>Specifies the maximum + verification depth, i.e. how far in a chain of certificates the + verification process can proceed before the verification is + considered to fail. Peer certificate = 0, CA certificate = 1, + higher level CA certificate = 2, etc. The value 2 thus means + that a chain can at most contain peer cert, CA cert, next CA + cert, and an additional CA cert. The default value is 1. + </item> + + <tag>{verify_fun, {Verifyfun :: fun(), InitialUserState :: term()}}</tag> + <item> + <p>The verification fun should be defined as:</p> + + <code> + fun(OtpCert :: #'OtpCertificate'{}, + Event :: {bad_cert, Reason :: atom()} | + {extension, #'Extension'{}}, InitialUserState :: term()) -> + {valid, UserState :: term()} | {fail, Reason :: term()} | + {unknown, UserState :: term()}. + </code> + + <p>The verify fun will be called during the X509-path + validation when an error or an extension unknown to the ssl + application is encountered. See + <seealso marker="public_key:application">public_key(3)</seealso> + for definition of #'OtpCertificate'{} and #'Extension'{}.</p> + + <p>If the verify callback fun returns {fail, Reason}, the + verification process is immediately stopped and an alert is + sent to the peer and the TLS/SSL handshake is terminated. If + the verify callback fun returns {valid, UserState}, the + verification process is continued. If the verify callback fun + always returns {valid, UserState}, the TLS/SSL handshake will + not be terminated with respect to verification failures and + the connection will be established. If called with an + extension unknown to the user application the return value + {unknown, UserState} should be used.</p> + + <p>The default verify_fun option in verify_peer mode:</p> + + <code> + {fun(_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState} + end, []} + </code> + + <p>The default verify_fun option in verify_none mode:</p> + + <code> + {fun(_,{bad_cert, unknown_ca}, UserState) -> + {valid, UserState}; + (_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState} + end, []} + </code> + + <p> Possible path validation errors: + {bad_cert, cert_expired}, + {bad_cert, invalid_issuer}, + {bad_cert, invalid_signature}, + {bad_cert, unknown_ca}, + {bad_cert, name_not_permitted}, + {bad_cert, missing_basic_constraint}, + {bad_cert, invalid_key_usage}, + {bad_cert, invalid_subject_altname}</p> + </item> + + </taglist> + + </section> + + <section> + <title>SSL OPTION DESCRIPTIONS - CLIENT SIDE</title> + + <p>Option described here are client specific or has a slightly different + meaning in the client than in the server.</p> + + <taglist> + <tag>{verify, verify_type()}</tag> + <item> In verify_none mode the x509-path validation error {bad_cert, unknown_ca} + will automatically be accepted. See also the verify_fun option. + </item> + <tag>{reuse_sessions, boolean()}</tag> + <item>Specifies if client should try to reuse sessions + when possible. + </item> + + </taglist> + </section> + + <section> + <title>SSL OPTION DESCRIPTIONS - SERVER SIDE</title> + + <p>Option described here are server specific or has a slightly different + meaning in the server than in the client.</p> + + <taglist> + + <tag>{dh, der_bin()}</tag> + <item>The DER encoded Diffie Hellman parameters. If this option + is supplied it will override the dhfile option. + </item> + + <tag>{dhfile, path()}</tag> + <item>Path to file containing PEM encoded Diffie Hellman parameters, + for the server to use if a cipher suite using Diffie Hellman key exchange + is negotiated. If not specified default parameters will be used. + </item> + + <tag>{verify, verify_type()}</tag> + <item>Servers only do the x509-path validation in verify_peer + mode, as it then will send a certificate request to the client + (this message is not sent if the verify option is verify_none) + and you may then also want to specify the option + fail_if_no_peer_cert. + </item> + + <tag>{fail_if_no_peer_cert, boolean()}</tag> + <item>Used together with {verify, verify_peer} by a ssl server. + If set to true, the server will fail if the client does not have + a certificate to send, i.e. sends a empty certificate, if set to + false it will only fail if the client sends a invalid + certificate (an empty certificate is considered valid). + </item> + <tag>{reuse_sessions, boolean()}</tag> - <item>Specifies if ssl sessions should be reused - when possible. + <item>Specifies if the server should agree to reuse sessions + when the clients request to do so. See also the reuse_session + option. </item> - <tag>{reuse_session, fun(SuggestedSessionId, - PeerCert, Compression, CipherSuite) -> boolean()}</tag> + <tag>{reuse_session, fun(SuggestedSessionId, + PeerCert, Compression, CipherSuite) -> boolean()}</tag> <item>Enables the ssl server to have a local policy for deciding if a session should be reused or not, only meaning full if <c>reuse_sessions</c> is set to true. @@ -252,14 +333,6 @@ end and CipherSuite of type ciphersuite(). </item> - <tag>{secure_renegotiate, boolean()}</tag> - <item>Specifies if to reject renegotiation attempt that does - not live up to RFC 5746. By default secure_renegotiate is - set to false e.i. secure renegotiation will be used if possible - but it will fallback to unsecure renegotiation if the peer - does not support RFC 5746. - </item> - </taglist> </section> @@ -316,7 +389,7 @@ end <v>Reason = term()</v> </type> <desc> <p>Upgrades a gen_tcp, or equivalent, - connected socket to a ssl socket e.i performs the + connected socket to a ssl socket i.e. performs the client-side ssl handshake.</p> </desc> </func> @@ -559,12 +632,12 @@ end </type> <desc> <p> Upgrades a gen_tcp, or - equivalent, socket to a ssl socket e.i performs the + equivalent, socket to a ssl socket i.e. performs the ssl server-side handshake.</p> - <p><note>Note that the listen socket should be in {active, false} mode + <p><warning>Note that the listen socket should be in {active, false} mode before telling the client that the server is ready to upgrade and calling this function, otherwise the upgrade may - or may not succeed depending on timing.</note></p> + or may not succeed depending on timing.</warning></p> </desc> </func> diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml index 4067fb8a22..7bcc12eb5f 100644 --- a/lib/ssl/doc/src/ssl_distribution.xml +++ b/lib/ssl/doc/src/ssl_distribution.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -36,7 +36,7 @@ <note><p>Note this documentation is written for the old ssl implementation and - will be updated for the new one once this functionallity is + will be updated for the new one once this functionality is supported by the new implementation.</p></note> </p> @@ -55,7 +55,7 @@ all participating Erlang nodes in a distributed system must use this distribution module.</p> <p>The security depends on how the connections are set up, one can - use key files or certificates to just get a crypted + use key files or certificates to just get a encrypted connection. One can also make the SSL package verify the certificates of other nodes to get additional security. Cookies are however always used as they can be used to @@ -179,7 +179,7 @@ Eshell V5.0 (abort with ^G) <c>certfile</c> can (and usually needs to) be specified as <c>client_certfile</c> and <c>server_certfile</c>. The <c>client_certfile</c> is used when the distribution initiates a - connection to another node and the <c>server_cerfile</c> is used + connection to another node and the <c>server_certfile</c> is used when accepting a connection from a remote node. </p> <p>The command line argument for specifying the SSL options is named <c>-ssl_dist_opt</c> and should be followed by an even number of diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml index 726b9a4eeb..6936408881 100644 --- a/lib/ssl/doc/src/ssl_protocol.xml +++ b/lib/ssl/doc/src/ssl_protocol.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE chapter SYSTEM "chapter.dtd"> <chapter> <header> <copyright> - <year>2003</year><year>2009</year> + <year>2003</year><year>2010</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -44,7 +44,7 @@ <section> <title>Security overview</title> - <p>To achive authentication and privacy the client and server will + <p>To achieve authentication and privacy the client and server will perform a TLS Handshake procedure before transmitting or receiving any data. During the handshake they agree on a protocol version and cryptographic algorithms, they generate shared secrets using public @@ -56,7 +56,7 @@ <title>Data Privacy and Integrity</title> <p>A <em>symmetric key</em> algorithm has one key only. The key is - used for both encryption and decryption. These algoritms are fast + used for both encryption and decryption. These algorithms are fast compared to public key algorithms (using two keys, a public and a private one) and are therefore typically used for encrypting bulk data. @@ -66,7 +66,7 @@ for each connection and are based on a secret negotiated in the TLS handshake. </p> - <p>The TLS handsake protocol and data transfer is run on top of + <p>The TLS handshake protocol and data transfer is run on top of the TLS Record Protocol that uses a keyed-hash MAC (Message Authenticity Code), or HMAC, to protect the message's data integrity. From the TLS RFC "A Message Authentication Code is a @@ -85,7 +85,7 @@ with the private key of the issuer of the certificate. A chain of trust is build by having the issuer in its turn being certified by an other certificate and so on until you reach the - so called root certificate that is self signed e.i. issued + so called root certificate that is self signed i.e. issued by itself.</p> <p>Certificates are issued by <em>certification diff --git a/lib/ssl/doc/src/ssl_session_cache_api.xml b/lib/ssl/doc/src/ssl_session_cache_api.xml index 7b70c6cf34..e0b07961fb 100644 --- a/lib/ssl/doc/src/ssl_session_cache_api.xml +++ b/lib/ssl/doc/src/ssl_session_cache_api.xml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> @@ -25,7 +25,7 @@ </header> <module>ssl_session_cache_api</module> <modulesummary>Defines the API for the TLS session cache so - that the datastorge scheme can be replaced by + that the data storage scheme can be replaced by defining a new callback module implementing this API.</modulesummary> <section> @@ -56,7 +56,7 @@ <v> Key = key()</v> </type> <desc> - <p> Delets a cache entry. Will only be called from the cache + <p> Deletes a cache entry. Will only be called from the cache handling process. </p> </desc> @@ -85,10 +85,10 @@ <v></v> </type> <desc> - <p>Performes possible initializations of the cache and returns + <p>Performs possible initializations of the cache and returns a reference to it that will be used as parameter to the other api functions. Will be called by the cache handling processes - init function, hence puting the same requierments on it as + init function, hence putting the same requirements on it as a normal process init function. </p> </desc> @@ -96,16 +96,16 @@ <func> <name>lookup(Cache, Key) -> Entry</name> - <fsummary> Looks up a cach entry.</fsummary> + <fsummary> Looks up a cache entry.</fsummary> <type> <v> Cache = cache_ref()</v> <v> Key = key()</v> <v> Entry = session() | undefined </v> </type> <desc> - <p>Looks up a cach entry. Should be callable from any - process. - </p> + <p>Looks up a cache entry. Should be callable from any + process. + </p> </desc> </func> @@ -127,7 +127,7 @@ <func> <name>terminate(Cache) -> _</name> <fsummary>Called by the process that handles the cache when it - is aboute to terminat.</fsummary> + is about to terminate.</fsummary> <type> <v>Cache = term() - as returned by init/0</v> </type> diff --git a/lib/ssl/examples/certs/Makefile b/lib/ssl/examples/certs/Makefile index 121fcc6950..b811b461dc 100644 --- a/lib/ssl/examples/certs/Makefile +++ b/lib/ssl/examples/certs/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# Copyright Ericsson AB 2003-2010. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -21,4 +21,41 @@ # Invoke with GNU make or clearmake -C gnu. # -include $(ERL_TOP)/make/run_make.mk +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(SSL_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN) + +TARGET_FILES= + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: $(TARGET_FILES) + +clean: + rm -fr $(TARGET_FILES) *~ *.beam + +docs: + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/examples/certs + tar cf - etc | \ + (cd $(RELSYSDIR)/examples/certs; tar xf -) + chmod -f -R ug+rw $(RELSYSDIR)/examples +release_docs_spec: diff --git a/lib/ssl/examples/certs/Makefile.in b/lib/ssl/examples/certs/Makefile.in deleted file mode 100644 index 4ea7aaf6dc..0000000000 --- a/lib/ssl/examples/certs/Makefile.in +++ /dev/null @@ -1,80 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2003-2009. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# - -# - -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -include ../../vsn.mk -VSN=$(SSL_VSN) - -RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN) - -EBIN = ebin -ETC = etc -SRC = src - -OPENSSL_CMD = @OPENSSL_CMD@ - -# We are generating more files than in the following list, but we take -# there existence as successful execution of make rules - -PEMS = cacerts.pem cert.pem key.pem - -PEMFILES = $(PEMS:%=$(ETC)/client/%) $(PEMS:%=$(ETC)/server/%) - -debug opt: $(PEMFILES) - -$(PEMFILES): done - -done: $(EBIN)/make_certs.beam - erl -noinput -pa $(EBIN) -run make_certs all $(OPENSSL_CMD) \ - -s erlang halt - echo >done - -$(EBIN)/make_certs.beam: $(SRC)/make_certs.erl - cd src; erlc -W -o ../$(EBIN) make_certs.erl - -clean: - rm -fr $(EBIN)/* $(SRC)/*~ $(SRC)/*.beam $(ETC) done \ - stderr.txt erl_crash.dump *~ - -docs: - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - $(INSTALL_DIR) $(RELSYSDIR)/examples/certs - tar cf - Makefile ebin etc rnd src | \ - (cd $(RELSYSDIR)/examples/certs; tar xf -) - chmod -f -R ug+rw $(RELSYSDIR)/examples - -release_docs_spec: - - - - - - - - diff --git a/lib/ssl/examples/certs/ebin/.gitignore b/lib/ssl/examples/certs/ebin/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 --- a/lib/ssl/examples/certs/ebin/.gitignore +++ /dev/null diff --git a/lib/ssl/examples/certs/etc/client/cacerts.pem b/lib/ssl/examples/certs/etc/client/cacerts.pem new file mode 100644 index 0000000000..cb19d3d41e --- /dev/null +++ b/lib/ssl/examples/certs/etc/client/cacerts.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIICizCCAfSgAwIBAgIFdMMs9fEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI +ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD +VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS +BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw +MDAwMDBaMH0xETAPBgNVBAMTCGVybGFuZ0NBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0 +ZXJAZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEP +MA0GA1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAgmHw2xApZqdzZOOPTzwHr1hRYd1OqbLOsXbAq6kJ +Kuu+qe5jAlMF3vnUhiHomuZeNZVJe3SP+JfBt3BHMjm2CLChCuNgfctKURMlEc/L +xo8fO1Jk9MD5mbG2Utx3m3gM6Liwt9fHVABlCTyB6/jXrK1tYpEG5CrwUXyy8Htl +jHECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAl +0tMEXWPgzXTpDuNmuKh6aGq9CuExUuEXXQQWPThzEuluA3aHFmObziQlMY1+KeO1 +AL0kpx0Yhvju/rfAJ+OF6MMni6hJoKlYTVml+fCY89A3nmY1rJHJavjHp0OIPGxh +4Sr+EcjROkqe8jE0DmbwmM6lzpwSJscxte+V6HvGRw== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIICiDCCAfGgAwIBAgIFSHyFNTEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI +ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD +VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS +BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw +MDAwMDBaMHoxDjAMBgNVBAMTBW90cENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0ZXJA +ZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEPMA0G +A1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAjEt9iy365+mTialKDKb3l2QPg71yavJA1ZC6aGC14X7x +KCm1FhUYsVKOlWjmC1VYJiCS01gvKqMXiogreHJGM93E+URlKkOm9kmOWQwLfFb8 +JLzafPi3/8TUdjl8UuIDHyPsoQiM2ZBDUVWezfl+CBsTYFO3U4Lqf9OKbCxTF78C +AwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAv6vHw +wK3MvxzlhDJIx7rUasOYJDZJyOt71KdOKeA7+ocbvDIblmV7sTbe3oQNqbSATZ6H +RUqHZdPhKIZ9wjEBSKdBTL8rc0TvbztMvd+i0rkTCL/bspQYchA2zCcjgkWqpaN4 +OhOjQR1+9/ntmaU/r5Ca7KmrXEf5XSQIGLSMag== +-----END CERTIFICATE----- + diff --git a/lib/ssl/examples/certs/etc/client/cert.pem b/lib/ssl/examples/certs/etc/client/cert.pem new file mode 100644 index 0000000000..a2f53aaf82 --- /dev/null +++ b/lib/ssl/examples/certs/etc/client/cert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIIChzCCAfCgAwIBAgIGAIsapa8BMA0GCSqGSIb3DQEBBQUAMHoxDjAMBgNVBAMT +BW90cENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0ZXJAZXJsYW5nLm9yZzESMBAGA1UE +BxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEPMA0GA1UEChMGZXJsYW5nMRQwEgYD +VQQLEwt0ZXN0aW5nIGRlcDAiGA8yMDEwMDkwMTAwMDAwMFoYDzIwMjUwODI4MDAw +MDAwWjB7MQ8wDQYDVQQDEwZjbGllbnQxIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBl +cmxhbmcub3JnMRIwEAYDVQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYD +VQQKEwZlcmxhbmcxFDASBgNVBAsTC3Rlc3RpbmcgZGVwMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQCTFBPkOO98fDY3j6MIxIGKp+rampfIay50Lx4+EnCnRSSV +wC+n0VVmP7V5SGFJpuXJzN0hvqPUWOOjiMTNlNRaGy0pqu2oMXWAPLOxHWL1wT53 +h2Zr3FUNU/N0Rvnkttse1KZJ9uYCLKUiuXXsv2rR62nH3OhRIiBHSAcSv0NRWwID +AQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAG8t6f1A +PF7xayGxtUpG2r6W5ETylC3ZIKPS2kfJk9aYi7AZNTp7/xTU6SgqvFBN8aBPzxCD +4jHrSNC8DSb4X1x9uimarb6qdZDHEdij+DRAd2eygJHZxEf7+8B4Fx34thQeU9hZ +S1Izke5AlsyFMkvB7h0anE4k9BfuU70vl6v5 +-----END CERTIFICATE----- + diff --git a/lib/ssl/examples/certs/etc/client/key.pem b/lib/ssl/examples/certs/etc/client/key.pem new file mode 100644 index 0000000000..4d55b08f4c --- /dev/null +++ b/lib/ssl/examples/certs/etc/client/key.pem @@ -0,0 +1,16 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQCTFBPkOO98fDY3j6MIxIGKp+rampfIay50Lx4+EnCnRSSVwC+n +0VVmP7V5SGFJpuXJzN0hvqPUWOOjiMTNlNRaGy0pqu2oMXWAPLOxHWL1wT53h2Zr +3FUNU/N0Rvnkttse1KZJ9uYCLKUiuXXsv2rR62nH3OhRIiBHSAcSv0NRWwIDAQAB +AoGACdIVYe/LTeydUihtInC8lZ2QuPgJmoBNocRjqJFipEihoL4scHAx25n1bBvB +I0HZphffzBkGp28oBAtl2LRPWXqu527unc/RWRfLMqSK1xNSq1DxD1a30zkrZPna +QiV65vEJuNSJTtlDy/Zqc/BVZXCpxWlzYQedZgkmf0Qse8ECQQCmaz02Yur8zC9f +eSQKU5OSzGw3bSIumEzziCfHdTheK6MEoccf5TCAyLXhZwA7QlKja4tFXfeyVxws +/LlnUJN9AkEA4j+xnOeYUyGKXL5i+BAbnqpI4MzPiq+IoCYkaRlD/wAws24r5HNI +ZQmEHWqD/NNzOf/A2XuyLtMiTGJPW/DftwJBAKKpJP6Ytuh6xz8BUCnLwO12Y7vV +LtjuQiCzD3aUa5EYA9HOMqxJPxxRkf0LyR0i2VUkE8+sZiPpov+R0cJa7p0CQQCj +40GUiArGRSiF7/+e84QeVfl+pb29F1QftiFv5DZmFEwy3Z572KpbTh5edJbxYHY6 +UDHxGHJFCvnwXNJhpkVXAkBJqfEfiMJ3Q/E5Gpf3sQizacouW92iiN8ojlF1oB80 +t34RysJH7SgI3gdMhTribCo2UUaV0StjR6yodPN+TB2J +-----END RSA PRIVATE KEY----- + diff --git a/lib/ssl/examples/certs/etc/erlangCA/cert.pem b/lib/ssl/examples/certs/etc/erlangCA/cert.pem new file mode 100644 index 0000000000..c4386494dc --- /dev/null +++ b/lib/ssl/examples/certs/etc/erlangCA/cert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICizCCAfSgAwIBAgIFdMMs9fEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI +ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD +VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS +BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw +MDAwMDBaMH0xETAPBgNVBAMTCGVybGFuZ0NBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0 +ZXJAZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEP +MA0GA1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAgmHw2xApZqdzZOOPTzwHr1hRYd1OqbLOsXbAq6kJ +Kuu+qe5jAlMF3vnUhiHomuZeNZVJe3SP+JfBt3BHMjm2CLChCuNgfctKURMlEc/L +xo8fO1Jk9MD5mbG2Utx3m3gM6Liwt9fHVABlCTyB6/jXrK1tYpEG5CrwUXyy8Htl +jHECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAl +0tMEXWPgzXTpDuNmuKh6aGq9CuExUuEXXQQWPThzEuluA3aHFmObziQlMY1+KeO1 +AL0kpx0Yhvju/rfAJ+OF6MMni6hJoKlYTVml+fCY89A3nmY1rJHJavjHp0OIPGxh +4Sr+EcjROkqe8jE0DmbwmM6lzpwSJscxte+V6HvGRw== +-----END CERTIFICATE----- + diff --git a/lib/ssl/examples/certs/etc/otpCA/cert.pem b/lib/ssl/examples/certs/etc/otpCA/cert.pem new file mode 100644 index 0000000000..8610621695 --- /dev/null +++ b/lib/ssl/examples/certs/etc/otpCA/cert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICiDCCAfGgAwIBAgIFSHyFNTEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI +ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD +VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS +BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw +MDAwMDBaMHoxDjAMBgNVBAMTBW90cENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0ZXJA +ZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEPMA0G +A1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAjEt9iy365+mTialKDKb3l2QPg71yavJA1ZC6aGC14X7x +KCm1FhUYsVKOlWjmC1VYJiCS01gvKqMXiogreHJGM93E+URlKkOm9kmOWQwLfFb8 +JLzafPi3/8TUdjl8UuIDHyPsoQiM2ZBDUVWezfl+CBsTYFO3U4Lqf9OKbCxTF78C +AwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAv6vHw +wK3MvxzlhDJIx7rUasOYJDZJyOt71KdOKeA7+ocbvDIblmV7sTbe3oQNqbSATZ6H +RUqHZdPhKIZ9wjEBSKdBTL8rc0TvbztMvd+i0rkTCL/bspQYchA2zCcjgkWqpaN4 +OhOjQR1+9/ntmaU/r5Ca7KmrXEf5XSQIGLSMag== +-----END CERTIFICATE----- + diff --git a/lib/ssl/examples/certs/etc/server/cacerts.pem b/lib/ssl/examples/certs/etc/server/cacerts.pem new file mode 100644 index 0000000000..cb19d3d41e --- /dev/null +++ b/lib/ssl/examples/certs/etc/server/cacerts.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIICizCCAfSgAwIBAgIFdMMs9fEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI +ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD +VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS +BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw +MDAwMDBaMH0xETAPBgNVBAMTCGVybGFuZ0NBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0 +ZXJAZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEP +MA0GA1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG +9w0BAQEFAAOBjQAwgYkCgYEAgmHw2xApZqdzZOOPTzwHr1hRYd1OqbLOsXbAq6kJ +Kuu+qe5jAlMF3vnUhiHomuZeNZVJe3SP+JfBt3BHMjm2CLChCuNgfctKURMlEc/L +xo8fO1Jk9MD5mbG2Utx3m3gM6Liwt9fHVABlCTyB6/jXrK1tYpEG5CrwUXyy8Htl +jHECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAl +0tMEXWPgzXTpDuNmuKh6aGq9CuExUuEXXQQWPThzEuluA3aHFmObziQlMY1+KeO1 +AL0kpx0Yhvju/rfAJ+OF6MMni6hJoKlYTVml+fCY89A3nmY1rJHJavjHp0OIPGxh +4Sr+EcjROkqe8jE0DmbwmM6lzpwSJscxte+V6HvGRw== +-----END CERTIFICATE----- + +-----BEGIN CERTIFICATE----- +MIICiDCCAfGgAwIBAgIFSHyFNTEwDQYJKoZIhvcNAQEFBQAwfTERMA8GA1UEAxMI +ZXJsYW5nQ0ExIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBlcmxhbmcub3JnMRIwEAYD +VQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYDVQQKEwZlcmxhbmcxFDAS +BgNVBAsTC3Rlc3RpbmcgZGVwMCIYDzIwMTAwOTAxMDAwMDAwWhgPMjAyNTA4Mjgw +MDAwMDBaMHoxDjAMBgNVBAMTBW90cENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0ZXJA +ZXJsYW5nLm9yZzESMBAGA1UEBxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEPMA0G +A1UEChMGZXJsYW5nMRQwEgYDVQQLEwt0ZXN0aW5nIGRlcDCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAjEt9iy365+mTialKDKb3l2QPg71yavJA1ZC6aGC14X7x +KCm1FhUYsVKOlWjmC1VYJiCS01gvKqMXiogreHJGM93E+URlKkOm9kmOWQwLfFb8 +JLzafPi3/8TUdjl8UuIDHyPsoQiM2ZBDUVWezfl+CBsTYFO3U4Lqf9OKbCxTF78C +AwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAv6vHw +wK3MvxzlhDJIx7rUasOYJDZJyOt71KdOKeA7+ocbvDIblmV7sTbe3oQNqbSATZ6H +RUqHZdPhKIZ9wjEBSKdBTL8rc0TvbztMvd+i0rkTCL/bspQYchA2zCcjgkWqpaN4 +OhOjQR1+9/ntmaU/r5Ca7KmrXEf5XSQIGLSMag== +-----END CERTIFICATE----- + diff --git a/lib/ssl/examples/certs/etc/server/cert.pem b/lib/ssl/examples/certs/etc/server/cert.pem new file mode 100644 index 0000000000..f26adb7f5c --- /dev/null +++ b/lib/ssl/examples/certs/etc/server/cert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIIChzCCAfCgAwIBAgIGANUxXM9BMA0GCSqGSIb3DQEBBQUAMHoxDjAMBgNVBAMT +BW90cENBMSAwHgYJKoZIhvcNAQkBFhF0ZXN0ZXJAZXJsYW5nLm9yZzESMBAGA1UE +BxMJU3RvY2tob2xtMQswCQYDVQQGEwJTRTEPMA0GA1UEChMGZXJsYW5nMRQwEgYD +VQQLEwt0ZXN0aW5nIGRlcDAiGA8yMDEwMDkwMTAwMDAwMFoYDzIwMjUwODI4MDAw +MDAwWjB7MQ8wDQYDVQQDEwZzZXJ2ZXIxIDAeBgkqhkiG9w0BCQEWEXRlc3RlckBl +cmxhbmcub3JnMRIwEAYDVQQHEwlTdG9ja2hvbG0xCzAJBgNVBAYTAlNFMQ8wDQYD +VQQKEwZlcmxhbmcxFDASBgNVBAsTC3Rlc3RpbmcgZGVwMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQCf4Htxr99lLs5W8QQw7jdakqyAkIjOW4aqH8sr4va4SvZ9 +Adq67k8jMHefCVZo+F8x4cwsBgB4aWzFIGBnvFTi6YsH27XW7f9O9IPCej8fdhRZ +4UAtNHa253buOWpDGla2JmIdkmfFvXFJycMIKbG5tYilVXoWKBMKmCwWaXz0nQID +AQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAGF5Pfwk +QDdwJup/mVITPxbBls4Yl7anDooUQsq8066lA1g54H/PRfXscGkyCFGh1ifXvf1L +psMRoBAdDHL/wSJplk3rRavkC94eBgnTFZmfKL6844g1j53yameiYL8IEVExYMBg +/XGyc0qwq57WT8B/K4aElrvlBlQ0wF3wN54M +-----END CERTIFICATE----- + diff --git a/lib/ssl/examples/certs/etc/server/key.pem b/lib/ssl/examples/certs/etc/server/key.pem new file mode 100644 index 0000000000..c1392ca557 --- /dev/null +++ b/lib/ssl/examples/certs/etc/server/key.pem @@ -0,0 +1,16 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQCf4Htxr99lLs5W8QQw7jdakqyAkIjOW4aqH8sr4va4SvZ9Adq6 +7k8jMHefCVZo+F8x4cwsBgB4aWzFIGBnvFTi6YsH27XW7f9O9IPCej8fdhRZ4UAt +NHa253buOWpDGla2JmIdkmfFvXFJycMIKbG5tYilVXoWKBMKmCwWaXz0nQIDAQAB +AoGAQIlma0r6W6bcRj4+Wd4fXCFvHuq5Psu1fYEeC5Yvz8761xVjjSfbrDHJZ9pm +FjOEgedK+s5lbDXqYVyjbdyZSugStBRocSmbG8SQHcAsxR2ZIkNzX2hYzB+lslWo +T3YJojDyB134O7XJznCu+ZFXP86jyJ1JT6k6a+OIHcwnJ+ECQQDYn57dY4Px3mEd +VBLStN3YkRF5oFyT+xk7IaKeLLB6n4gCnoVbBoHut7PFbPYPzoNzEwPk3MQKDIHb +Kig3S5CpAkEAvPA1VmoJWAlN6kUi+F2L8HXEArzE8x7vwdsslrwMKUe4dFS+ZC/7 +5iDOaxcZ7TYkCgwzBt341++DCgP6j3fY1QJBALB6AcOcwi52m6l4B8mu3ZkEPjdX +BHTuONTqhv/TqoaLlxODL2NDvvDKqeMp7KBd/srt79swW2lQXS4+fvrlTdkCQQCm +zxj4O1QWkthkfje6ubSkTwUIOatUzrp1F9GNH2dJRtX2dx9FCwxGCC7WY6XzRXqa +GF0wsedSllbGD+82nWQlAkAicMGqCqRq4hKR/cVmFatOqKVWCVkx6OFF2FhuiI5Z +h5eIOPGCt8dVRs1P9DNSld/D98Sfm65m85z8BtXovvYV +-----END RSA PRIVATE KEY----- + diff --git a/lib/ssl/examples/certs/rnd/RAND b/lib/ssl/examples/certs/rnd/RAND Binary files differdeleted file mode 100644 index 70997bd01f..0000000000 --- a/lib/ssl/examples/certs/rnd/RAND +++ /dev/null diff --git a/lib/ssl/examples/certs/src/make_certs.erl b/lib/ssl/examples/certs/src/make_certs.erl index c374836568..fe267bed28 100644 --- a/lib/ssl/examples/certs/src/make_certs.erl +++ b/lib/ssl/examples/certs/src/make_certs.erl @@ -1,261 +1,48 @@ -%% The purpose of this module is to create example certificates for -%% testing. -%% Run it as: -%% -%% erl -noinput -run make_certs all "/path/to/openssl" -s erlang halt -%% +%% The purpose of this module is to log how the example certs where created, +%% it requires erl_make_certs found in the test directory. -module(make_certs). --export([all/0, all/1]). - --record(dn, {commonName, - organizationalUnitName = "Erlang OTP", - organizationName = "Ericsson AB", - localityName = "Stockholm", - countryName = "SE", - emailAddress = "peter@erix.ericsson.se"}). +-export([all/0]). all() -> - all(["openssl"]). - -all([OpenSSLCmd]) -> - Root = filename:dirname(filename:dirname((code:which(?MODULE)))), - %% io:fwrite("Root : ~s~n", [Root]), - NRoot = filename:join([Root, "etc"]), - file:make_dir(NRoot), - create_rnd(Root, "etc"), % For all requests - rootCA(NRoot, OpenSSLCmd, "erlangCA"), - intermediateCA(NRoot, OpenSSLCmd, "otpCA", "erlangCA"), - endusers(NRoot, OpenSSLCmd, "otpCA", ["client", "server"]), - collect_certs(NRoot, ["erlangCA", "otpCA"], ["client", "server"]), - remove_rnd(Root, "etc"). - -rootCA(Root, OpenSSLCmd, Name) -> - create_ca_dir(Root, Name, ca_cnf(Name)), - DN = #dn{commonName = Name}, - create_self_signed_cert(Root, OpenSSLCmd, Name, req_cnf(DN)), - ok. - -intermediateCA(Root, OpenSSLCmd, CA, ParentCA) -> - CA = "otpCA", - create_ca_dir(Root, CA, ca_cnf(CA)), - CARoot = filename:join([Root, CA]), - DN = #dn{commonName = CA}, - CnfFile = filename:join([CARoot, "req.cnf"]), - file:write_file(CnfFile, req_cnf(DN)), - KeyFile = filename:join([CARoot, "private", "key.pem"]), - ReqFile = filename:join([CARoot, "req.pem"]), - create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile), - CertFile = filename:join([CARoot, "cert.pem"]), - sign_req(Root, OpenSSLCmd, ParentCA, "ca_cert", ReqFile, CertFile). - -endusers(Root, OpenSSLCmd, CA, Users) -> - lists:foreach(fun(User) -> enduser(Root, OpenSSLCmd, CA, User) end, Users). - -enduser(Root, OpenSSLCmd, CA, User) -> - UsrRoot = filename:join([Root, User]), - file:make_dir(UsrRoot), - CnfFile = filename:join([UsrRoot, "req.cnf"]), - DN = #dn{commonName = User}, - file:write_file(CnfFile, req_cnf(DN)), - KeyFile = filename:join([UsrRoot, "key.pem"]), - ReqFile = filename:join([UsrRoot, "req.pem"]), - create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile), - CertFile = filename:join([UsrRoot, "cert.pem"]), - sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFile). - -collect_certs(Root, CAs, Users) -> - Bins = lists:foldr( - fun(CA, Acc) -> - File = filename:join([Root, CA, "cert.pem"]), - {ok, Bin} = file:read_file(File), - [Bin, "\n" | Acc] - end, [], CAs), - lists:foreach( - fun(User) -> - File = filename:join([Root, User, "cacerts.pem"]), - file:write_file(File, Bins) - end, Users). - -create_self_signed_cert(Root, OpenSSLCmd, CAName, Cnf) -> - CARoot = filename:join([Root, CAName]), - CnfFile = filename:join([CARoot, "req.cnf"]), - file:write_file(CnfFile, Cnf), - KeyFile = filename:join([CARoot, "private", "key.pem"]), - CertFile = filename:join([CARoot, "cert.pem"]), - Cmd = [OpenSSLCmd, " req" - " -new" - " -x509" - " -config ", CnfFile, - " -keyout ", KeyFile, - " -out ", CertFile], - Env = [{"ROOTDIR", Root}], - cmd(Cmd, Env). - -create_ca_dir(Root, CAName, Cnf) -> - CARoot = filename:join([Root, CAName]), - file:make_dir(CARoot), - create_dirs(CARoot, ["certs", "crl", "newcerts", "private"]), - create_rnd(Root, filename:join([CAName, "private"])), - create_files(CARoot, [{"serial", "01\n"}, - {"index.txt", ""}, - {"ca.cnf", Cnf}]). - -create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile) -> - Cmd = [OpenSSLCmd, " req" - " -new" - " -config ", CnfFile, - " -keyout ", KeyFile, - " -out ", ReqFile], - Env = [{"ROOTDIR", Root}], - cmd(Cmd, Env). - -sign_req(Root, OpenSSLCmd, CA, CertType, ReqFile, CertFile) -> - CACnfFile = filename:join([Root, CA, "ca.cnf"]), - Cmd = [OpenSSLCmd, " ca" - " -batch" - " -notext" - " -config ", CACnfFile, - " -extensions ", CertType, - " -in ", ReqFile, - " -out ", CertFile], - Env = [{"ROOTDIR", Root}], - cmd(Cmd, Env). + LongTime = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+15*365), + Validity = {date(), LongTime}, + Subject = [{email, "tester@erlang.org"}, + {city, "Stockholm"}, + {country, "SE"}, + {org, "erlang"}, + {org_unit, "testing dep"}], + + RootCa = erl_make_certs:make_cert([{validity, Validity}, {subject, [{name, "erlangCA"}|Subject]}]), + ImedCa = erl_make_certs:make_cert([{issuer, RootCa}, {validity, Validity}, + {subject, [{name, "otpCA"}|Subject]}]), + ClientCa = erl_make_certs:make_cert([{issuer, ImedCa}, {validity, Validity}, + {subject, [{name, "client"}|Subject]}]), + ServerCa = erl_make_certs:make_cert([{issuer, ImedCa}, {validity, Validity}, + {subject, [{name, "server"}|Subject]}]), + + Root0 = filename:dirname(filename:dirname((code:which(?MODULE)))), + Root = filename:join([Root0, "etc"]), file:make_dir(Root), + CaPath = filename:join([Root, "erlangCA"]), file:make_dir(CaPath), + IPath = filename:join([Root, "otpCA"]), file:make_dir(IPath), + CPath = filename:join([Root, "client"]), file:make_dir(CPath), + SPath = filename:join([Root, "server"]), file:make_dir(SPath), + + erl_make_certs:write_pem(CaPath,"cert", RootCa), + erl_make_certs:write_pem(IPath, "cert", ImedCa), + + {ok, CaBin0} = file:read_file(filename:join(CaPath, "cert.pem")), + {ok, CaBin1} = file:read_file(filename:join(IPath, "cert.pem")), + CaBin = <<CaBin0/binary, CaBin1/binary>>, + + erl_make_certs:write_pem(CPath, "cert", ClientCa), + ok = file:write_file(filename:join(CPath, "cacerts.pem"), CaBin), + erl_make_certs:write_pem(SPath, "cert", ServerCa), + ok = file:write_file(filename:join(SPath, "cacerts.pem"), CaBin), -%% -%% Misc -%% - -create_dirs(Root, Dirs) -> - lists:foreach(fun(Dir) -> - file:make_dir(filename:join([Root, Dir])) end, - Dirs). - -create_files(Root, NameContents) -> - lists:foreach( - fun({Name, Contents}) -> - file:write_file(filename:join([Root, Name]), Contents) end, - NameContents). - -create_rnd(Root, Dir) -> - From = filename:join([Root, "rnd", "RAND"]), - To = filename:join([Root, Dir, "RAND"]), - file:copy(From, To). - -remove_rnd(Root, Dir) -> - File = filename:join([Root, Dir, "RAND"]), - file:delete(File). - -cmd(Cmd, Env) -> - FCmd = lists:flatten(Cmd), - Port = open_port({spawn, FCmd}, [stream, eof, exit_status, - {env, Env}]), - eval_cmd(Port). - -eval_cmd(Port) -> - receive - {Port, {data, _}} -> - eval_cmd(Port); - {Port, eof} -> - ok - end, - receive - {Port, {exit_status, Status}} when Status /= 0 -> - %% io:fwrite("exit status: ~w~n", [Status]), - erlang:halt(Status) - after 0 -> - ok - end. - -%% -%% Contents of configuration files -%% - -req_cnf(DN) -> - ["# Purpose: Configuration for requests (end users and CAs)." - "\n" - "ROOTDIR = $ENV::ROOTDIR\n" - "\n" - - "[req]\n" - "input_password = secret\n" - "output_password = secret\n" - "default_bits = 1024\n" - "RANDFILE = $ROOTDIR/RAND\n" - "encrypt_key = no\n" - "default_md = sha1\n" - "#string_mask = pkix\n" - "x509_extensions = ca_ext\n" - "prompt = no\n" - "distinguished_name= name\n" - "\n" - - "[name]\n" - "commonName = ", DN#dn.commonName, "\n" - "organizationalUnitName = ", DN#dn.organizationalUnitName, "\n" - "organizationName = ", DN#dn.organizationName, "\n" - "localityName = ", DN#dn.localityName, "\n" - "countryName = ", DN#dn.countryName, "\n" - "emailAddress = ", DN#dn.emailAddress, "\n" - "\n" - - "[ca_ext]\n" - "basicConstraints = critical, CA:true\n" - "keyUsage = cRLSign, keyCertSign\n" - "subjectKeyIdentifier = hash\n" - "subjectAltName = email:copy\n"]. - - -ca_cnf(CA) -> - ["# Purpose: Configuration for CAs.\n" - "\n" - "ROOTDIR = $ENV::ROOTDIR\n" - "default_ca = ca\n" - "\n" - - "[ca]\n" - "dir = $ROOTDIR/", CA, "\n" - "certs = $dir/certs\n" - "crl_dir = $dir/crl\n" - "database = $dir/index.txt\n" - "new_certs_dir = $dir/newcerts\n" - "certificate = $dir/cert.pem\n" - "serial = $dir/serial\n" - "crl = $dir/crl.pem\n" - "private_key = $dir/private/key.pem\n" - "RANDFILE = $dir/private/RAND\n" - "\n" - "x509_extensions = user_cert\n" - "default_days = 3600\n" - "default_md = sha1\n" - "preserve = no\n" - "policy = policy_match\n" - "\n" - - "[policy_match]\n" - "commonName = supplied\n" - "organizationalUnitName = optional\n" - "organizationName = match\n" - "countryName = match\n" - "localityName = match\n" - "emailAddress = supplied\n" - "\n" - - "[user_cert]\n" - "basicConstraints = CA:false\n" - "keyUsage = nonRepudiation, digitalSignature, keyEncipherment\n" - "subjectKeyIdentifier = hash\n" - "authorityKeyIdentifier = keyid,issuer:always\n" - "subjectAltName = email:copy\n" - "issuerAltName = issuer:copy\n" - "\n" - - "[ca_cert]\n" - "basicConstraints = critical,CA:true\n" - "keyUsage = cRLSign, keyCertSign\n" - "subjectKeyIdentifier = hash\n" - "authorityKeyIdentifier = keyid:always,issuer:always\n" - "subjectAltName = email:copy\n" - "issuerAltName = issuer:copy\n"]. - + file:delete(filename:join(CaPath, "cert_key.pem")), + file:delete(filename:join(IPath, "cert_key.pem")), + file:rename(filename:join(CPath, "cert_key.pem"), filename:join(CPath, "key.pem")), + file:rename(filename:join(SPath, "cert_key.pem"), filename:join(SPath, "key.pem")), + ok. diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index 6e26f05c3d..cc01b35b64 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -80,6 +80,7 @@ stop() -> -spec connect(host() | port(), list()) -> {ok, #sslsocket{}}. -spec connect(host() | port(), list() | port_num(), timeout() | list()) -> {ok, #sslsocket{}}. -spec connect(host() | port(), port_num(), list(), timeout()) -> {ok, #sslsocket{}}. + %% %% Description: Connect to a ssl server. %%-------------------------------------------------------------------- @@ -375,7 +376,7 @@ cipher_suites(openssl) -> [ssl_cipher:openssl_suite_name(S) || S <- ssl_cipher:suites(Version)]. %%-------------------------------------------------------------------- --spec getopts(#sslsocket{}, [atom()]) -> {ok, [{atom(), term()}]}| {error, reason()}. +-spec getopts(#sslsocket{}, [atom()]) -> {ok, [{atom(), term()}]}| {error, reason()}. %% %% Description: %%-------------------------------------------------------------------- @@ -522,59 +523,64 @@ old_listen(Port, Options) -> {ok, Pid} = ssl_broker:start_broker(listener), ssl_broker:listen(Pid, Port, Options). -handle_options(Opts0, Role) -> +handle_options(Opts0, _Role) -> Opts = proplists:expand([{binary, [{mode, binary}]}, {list, [{mode, list}]}], Opts0), ReuseSessionFun = fun(_, _, _, _) -> true end, - AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc; - (Other, Acc) -> [Other | Acc] - end, - - VerifyFun = - fun(ErrorList) -> - case lists:foldl(AcceptBadCa, [], ErrorList) of - [] -> true; - [_|_] -> false - end - end, + VerifyNoneFun = + {fun(_,{bad_cert, unknown_ca}, UserState) -> + {valid, UserState}; + (_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState} + end, []}, - UserFailIfNoPeerCert = validate_option(fail_if_no_peer_cert, - proplists:get_value(fail_if_no_peer_cert, Opts, false)), + UserFailIfNoPeerCert = handle_option(fail_if_no_peer_cert, Opts, false), + UserVerifyFun = handle_option(verify_fun, Opts, undefined), + CaCerts = handle_option(cacerts, Opts, undefined), - {Verify, FailIfNoPeerCert, CaCertDefault} = + {Verify, FailIfNoPeerCert, CaCertDefault, VerifyFun} = %% Handle 0, 1, 2 for backwards compatibility case proplists:get_value(verify, Opts, verify_none) of 0 -> - {verify_none, false, ca_cert_default(verify_none, Role)}; + {verify_none, false, + ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun}; 1 -> - {verify_peer, false, ca_cert_default(verify_peer, Role)}; + {verify_peer, false, + ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun}; 2 -> - {verify_peer, true, ca_cert_default(verify_peer, Role)}; + {verify_peer, true, + ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun}; verify_none -> - {verify_none, false, ca_cert_default(verify_none, Role)}; + {verify_none, false, + ca_cert_default(verify_none, VerifyNoneFun, CaCerts), VerifyNoneFun}; verify_peer -> - {verify_peer, UserFailIfNoPeerCert, ca_cert_default(verify_peer, Role)}; + {verify_peer, UserFailIfNoPeerCert, + ca_cert_default(verify_peer, UserVerifyFun, CaCerts), UserVerifyFun}; Value -> throw({error, {eoptions, {verify, Value}}}) - end, + end, CertFile = handle_option(certfile, Opts, ""), SSLOptions = #ssl_options{ versions = handle_option(versions, Opts, []), verify = validate_option(verify, Verify), - verify_fun = handle_option(verify_fun, Opts, VerifyFun), + verify_fun = VerifyFun, fail_if_no_peer_cert = FailIfNoPeerCert, verify_client_once = handle_option(verify_client_once, Opts, false), - validate_extensions_fun = handle_option(validate_extensions_fun, Opts, undefined), depth = handle_option(depth, Opts, 1), + cert = handle_option(cert, Opts, undefined), certfile = CertFile, - keyfile = handle_option(keyfile, Opts, CertFile), key = handle_option(key, Opts, undefined), + keyfile = handle_option(keyfile, Opts, CertFile), password = handle_option(password, Opts, ""), + cacerts = CaCerts, cacertfile = handle_option(cacertfile, Opts, CaCertDefault), + dh = handle_option(dh, Opts, undefined), dhfile = handle_option(dhfile, Opts, undefined), ciphers = handle_option(ciphers, Opts, []), %% Server side option @@ -586,10 +592,10 @@ handle_options(Opts0, Role) -> }, CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}), - SslOptions = [versions, verify, verify_fun, validate_extensions_fun, + SslOptions = [versions, verify, verify_fun, fail_if_no_peer_cert, verify_client_once, - depth, certfile, keyfile, - key, password, cacertfile, dhfile, ciphers, + depth, cert, certfile, key, keyfile, + password, cacerts, cacertfile, dh, dhfile, ciphers, debug, reuse_session, reuse_sessions, ssl_imp, cb_info, renegotiate_at, secure_renegotiate], @@ -613,7 +619,21 @@ validate_option(ssl_imp, Value) when Value == new; Value == old -> validate_option(verify, Value) when Value == verify_none; Value == verify_peer -> Value; -validate_option(verify_fun, Value) when is_function(Value) -> +validate_option(verify_fun, undefined) -> + undefined; +%% Backwards compatibility +validate_option(verify_fun, Fun) when is_function(Fun) -> + {fun(_,{bad_cert, _} = Reason, OldFun) -> + case OldFun([Reason]) of + true -> + {valid, OldFun}; + false -> + {fail, Reason} + end; + (_,{extension, _}, UserState) -> + {unknown, UserState} + end, Fun}; +validate_option(verify_fun, {Fun, _} = Value) when is_function(Fun) -> Value; validate_option(fail_if_no_peer_cert, Value) when Value == true; Value == false -> @@ -621,29 +641,38 @@ validate_option(fail_if_no_peer_cert, Value) validate_option(verify_client_once, Value) when Value == true; Value == false -> Value; - -validate_option(validate_extensions_fun, Value) when Value == undefined; is_function(Value) -> - Value; validate_option(depth, Value) when is_integer(Value), Value >= 0, Value =< 255-> Value; +validate_option(cert, Value) when Value == undefined; + is_binary(Value) -> + Value; validate_option(certfile, Value) when is_list(Value) -> Value; + +validate_option(key, undefined) -> + undefined; +validate_option(key, {KeyType, Value}) when is_binary(Value), + KeyType == rsa; + KeyType == dsa -> + {KeyType, Value}; validate_option(keyfile, Value) when is_list(Value) -> Value; -validate_option(key, Value) when Value == undefined; - is_tuple(Value) -> - %% element(1, Value)=='RSAPrivateKey' -> - Value; validate_option(password, Value) when is_list(Value) -> Value; +validate_option(cacerts, Value) when Value == undefined; + is_list(Value) -> + Value; %% certfile must be present in some cases otherwhise it can be set %% to the empty string. validate_option(cacertfile, undefined) -> ""; validate_option(cacertfile, Value) when is_list(Value), Value =/= "" -> Value; +validate_option(dh, Value) when Value == undefined; + is_binary(Value) -> + Value; validate_option(dhfile, undefined = Value) -> Value; validate_option(dhfile, Value) when is_list(Value), Value =/= "" -> @@ -701,14 +730,16 @@ validate_inet_option(active, Value) validate_inet_option(_, _) -> ok. -ca_cert_default(verify_none, _) -> +%% The option cacerts overrides cacertsfile +ca_cert_default(_,_, [_|_]) -> + undefined; +ca_cert_default(verify_none, _, _) -> undefined; -%% Client may leave verification up to the user -ca_cert_default(verify_peer, client) -> +ca_cert_default(verify_peer, {Fun,_}, _) when is_function(Fun) -> undefined; -%% Server that wants to verify_peer must have +%% Server that wants to verify_peer and has no verify_fun must have %% some trusted certs. -ca_cert_default(verify_peer, server) -> +ca_cert_default(verify_peer, undefined, _) -> "". emulated_options() -> diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl index 5026c760bd..6cf57ced81 100644 --- a/lib/ssl/src/ssl_certificate.erl +++ b/lib/ssl/src/ssl_certificate.erl @@ -34,7 +34,8 @@ -export([trusted_cert_and_path/2, certificate_chain/2, file_to_certificats/1, - validate_extensions/6, + %validate_extensions/6, + validate_extension/3, is_valid_extkey_usage/2, is_valid_key_usage/2, select_extension/2, @@ -110,32 +111,25 @@ file_to_certificats(File) -> {ok, List} = ssl_manager:cache_pem_file(File), [Bin || {'Certificate', Bin, not_encrypted} <- List]. %%-------------------------------------------------------------------- --spec validate_extensions([#'Extension'{}], term(), [#'Extension'{}], - boolean(), list(), client | server) -> {[#'Extension'{}], term(), list()}. +-spec validate_extension(term(), #'Extension'{}, term()) -> {valid, term()} | + {fail, tuple()} | + {unknown, term()}. %% %% Description: Validates ssl/tls specific extensions %%-------------------------------------------------------------------- -validate_extensions([], ValidationState, UnknownExtensions, _, AccErr, _) -> - {UnknownExtensions, ValidationState, AccErr}; - -validate_extensions([#'Extension'{extnID = ?'id-ce-extKeyUsage', - extnValue = KeyUse, - critical = true} | Rest], - ValidationState, UnknownExtensions, Verify, AccErr0, Role) -> +validate_extension(_,{extension, #'Extension'{extnID = ?'id-ce-extKeyUsage', + extnValue = KeyUse, + critical = true}}, Role) -> case is_valid_extkey_usage(KeyUse, Role) of true -> - validate_extensions(Rest, ValidationState, UnknownExtensions, - Verify, AccErr0, Role); + {valid, Role}; false -> - AccErr = - not_valid_extension({bad_cert, invalid_ext_key_usage}, Verify, AccErr0), - validate_extensions(Rest, ValidationState, UnknownExtensions, Verify, AccErr, Role) + {fail, {bad_cert, invalid_ext_key_usage}} end; - -validate_extensions([Extension | Rest], ValidationState, UnknownExtensions, - Verify, AccErr, Role) -> - validate_extensions(Rest, ValidationState, [Extension | UnknownExtensions], - Verify, AccErr, Role). +validate_extension(_, {bad_cert, _} = Reason, _) -> + {fail, Reason}; +validate_extension(_, _, Role) -> + {unknown, Role}. %%-------------------------------------------------------------------- -spec is_valid_key_usage(list(), term()) -> boolean(). @@ -248,8 +242,3 @@ is_valid_extkey_usage(KeyUse, client) -> is_valid_extkey_usage(KeyUse, server) -> %% Server wants to verify client is_valid_key_usage(KeyUse, ?'id-kp-clientAuth'). - -not_valid_extension(Error, true, _) -> - throw(Error); -not_valid_extension(Error, false, AccErrors) -> - [Error | AccErrors]. diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl index 00d3079cb3..86477f369d 100644 --- a/lib/ssl/src/ssl_certificate_db.erl +++ b/lib/ssl/src/ssl_certificate_db.erl @@ -74,12 +74,16 @@ lookup_cached_certs(File) -> ets:lookup(certificate_db_name(), {file, File}). %%-------------------------------------------------------------------- --spec add_trusted_certs(pid(), string(), certdb_ref()) -> {ok, certdb_ref()}. +-spec add_trusted_certs(pid(), string() | {der, list()}, certdb_ref()) -> {ok, certdb_ref()}. %% %% Description: Adds the trusted certificates from file <File> to the %% runtime database. Returns Ref that should be handed to lookup_trusted_cert %% together with the cert serialnumber and issuer. %%-------------------------------------------------------------------- +add_trusted_certs(_Pid, {der, DerList}, [CerDb, _,_]) -> + NewRef = make_ref(), + add_certs_from_der(DerList, NewRef, CerDb), + {ok, NewRef}; add_trusted_certs(Pid, File, [CertsDb, FileToRefDb, PidToFileDb]) -> Ref = case lookup(File, FileToRefDb) of undefined -> @@ -93,7 +97,6 @@ add_trusted_certs(Pid, File, [CertsDb, FileToRefDb, PidToFileDb]) -> end, insert(Pid, File, PidToFileDb), {ok, Ref}. - %%-------------------------------------------------------------------- -spec cache_pem_file(pid(), string(), certdb_ref()) -> term(). %% @@ -202,16 +205,20 @@ lookup(Key, Db) -> remove_certs(Ref, CertsDb) -> ets:match_delete(CertsDb, {{Ref, '_', '_'}, '_'}). +add_certs_from_der(DerList, Ref, CertsDb) -> + Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end, + [Add(Cert) || Cert <- DerList]. + add_certs_from_file(File, Ref, CertsDb) -> - Add = fun(Cert) -> - ErlCert = public_key:pkix_decode_cert(Cert, otp), - TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate, - SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber, - Issuer = public_key:pkix_normalize_name( - TBSCertificate#'OTPTBSCertificate'.issuer), - insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb) - end, + Add = fun(Cert) -> add_certs(Cert, Ref, CertsDb) end, {ok, PemBin} = file:read_file(File), PemEntries = public_key:pem_decode(PemBin), [Add(Cert) || {'Certificate', Cert, not_encrypted} <- PemEntries]. +add_certs(Cert, Ref, CertsDb) -> + ErlCert = public_key:pkix_decode_cert(Cert, otp), + TBSCertificate = ErlCert#'OTPCertificate'.tbsCertificate, + SerialNumber = TBSCertificate#'OTPTBSCertificate'.serialNumber, + Issuer = public_key:pkix_normalize_name( + TBSCertificate#'OTPTBSCertificate'.issuer), + insert({Ref, SerialNumber, Issuer}, {Cert,ErlCert}, CertsDb). diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index dd8f77a0ca..c94199c336 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -500,8 +500,7 @@ certify(#certificate{} = Cert, ssl_options = Opts} = State) -> case ssl_handshake:certify(Cert, CertDbRef, Opts#ssl_options.depth, Opts#ssl_options.verify, - Opts#ssl_options.verify_fun, - Opts#ssl_options.validate_extensions_fun, Role) of + Opts#ssl_options.verify_fun, Role) of {PeerCert, PublicKeyInfo} -> handle_peer_cert(PeerCert, PublicKeyInfo, State#state{client_certificate_requested = false}); @@ -1035,23 +1034,32 @@ ssl_init(SslOpts, Role) -> PrivateKey = init_private_key(SslOpts#ssl_options.key, SslOpts#ssl_options.keyfile, SslOpts#ssl_options.password, Role), - DHParams = init_diffie_hellman(SslOpts#ssl_options.dhfile, Role), + DHParams = init_diffie_hellman(SslOpts#ssl_options.dh, SslOpts#ssl_options.dhfile, Role), {ok, CertDbRef, CacheRef, OwnCert, PrivateKey, DHParams}. -init_certificates(#ssl_options{cacertfile = CACertFile, - certfile = CertFile}, Role) -> + +init_certificates(#ssl_options{cacerts = CaCerts, + cacertfile = CACertFile, + certfile = CertFile, + cert = Cert}, Role) -> {ok, CertDbRef, CacheRef} = try - {ok, _, _} = ssl_manager:connection_init(CACertFile, Role) + Certs = case CaCerts of + undefined -> + CACertFile; + _ -> + {der, CaCerts} + end, + {ok, _, _} = ssl_manager:connection_init(Certs, Role) catch Error:Reason -> handle_file_error(?LINE, Error, Reason, CACertFile, ecacertfile, erlang:get_stacktrace()) end, - init_certificates(CertDbRef, CacheRef, CertFile, Role). + init_certificates(Cert, CertDbRef, CacheRef, CertFile, Role). -init_certificates(CertDbRef, CacheRef, CertFile, client) -> +init_certificates(undefined, CertDbRef, CacheRef, CertFile, client) -> try [OwnCert] = ssl_certificate:file_to_certificats(CertFile), {ok, CertDbRef, CacheRef, OwnCert} @@ -1059,7 +1067,7 @@ init_certificates(CertDbRef, CacheRef, CertFile, client) -> {ok, CertDbRef, CacheRef, undefined} end; -init_certificates(CertDbRef, CacheRef, CertFile, server) -> +init_certificates(undefined, CertDbRef, CacheRef, CertFile, server) -> try [OwnCert] = ssl_certificate:file_to_certificats(CertFile), {ok, CertDbRef, CacheRef, OwnCert} @@ -1067,7 +1075,9 @@ init_certificates(CertDbRef, CacheRef, CertFile, server) -> Error:Reason -> handle_file_error(?LINE, Error, Reason, CertFile, ecertfile, erlang:get_stacktrace()) - end. + end; +init_certificates(Cert, CertDbRef, CacheRef, _, _) -> + {ok, CertDbRef, CacheRef, Cert}. init_private_key(undefined, "", _Password, client) -> undefined; @@ -1084,8 +1094,10 @@ init_private_key(undefined, KeyFile, Password, _) -> erlang:get_stacktrace()) end; -init_private_key(PrivateKey, _, _,_) -> - PrivateKey. +init_private_key({rsa, PrivateKey}, _, _,_) -> + public_key:der_decode('RSAPrivateKey', PrivateKey); +init_private_key({dsa, PrivateKey},_,_,_) -> + public_key:der_decode('DSAPrivateKey', PrivateKey). handle_file_error(Line, Error, {badmatch, Reason}, File, Throw, Stack) -> file_error(Line, Error, Reason, File, Throw, Stack); @@ -1099,11 +1111,13 @@ file_error(Line, Error, Reason, File, Throw, Stack) -> error_logger:error_report(Report), throw(Throw). -init_diffie_hellman(_, client) -> +init_diffie_hellman(Params, _,_) when is_binary(Params)-> + public_key:der_decode('DHParameter', Params); +init_diffie_hellman(_,_, client) -> undefined; -init_diffie_hellman(undefined, _) -> +init_diffie_hellman(_,undefined, _) -> ?DEFAULT_DIFFIE_HELLMAN_PARAMS; -init_diffie_hellman(DHParamFile, server) -> +init_diffie_hellman(_, DHParamFile, server) -> try {ok, List} = ssl_manager:cache_pem_file(DHParamFile), case [Entry || Entry = {'DHParameter', _ , _} <- List] of diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index add5147fb4..99bc47f04b 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -32,15 +32,13 @@ -include_lib("public_key/include/public_key.hrl"). -export([master_secret/4, client_hello/5, server_hello/4, hello/4, - hello_request/0, certify/7, certificate/3, - client_certificate_verify/6, - certificate_verify/6, certificate_request/2, - key_exchange/2, server_key_exchange_hash/2, finished/4, - verify_connection/5, - get_tls_handshake/2, decode_client_key/3, - server_hello_done/0, sig_alg/1, - encode_handshake/3, init_hashes/0, - update_hashes/2, decrypt_premaster_secret/2]). + hello_request/0, certify/6, certificate/3, + client_certificate_verify/6, certificate_verify/6, + certificate_request/2, key_exchange/2, server_key_exchange_hash/2, + finished/4, verify_connection/5, get_tls_handshake/2, + decode_client_key/3, server_hello_done/0, sig_alg/1, + encode_handshake/3, init_hashes/0, update_hashes/2, + decrypt_premaster_secret/2]). -type tls_handshake() :: #client_hello{} | #server_hello{} | #server_hello_done{} | #certificate{} | #certificate_request{} | @@ -177,59 +175,55 @@ hello(#client_hello{client_version = ClientVersion, random = Random, %%-------------------------------------------------------------------- -spec certify(#certificate{}, term(), integer() | nolimit, - verify_peer | verify_none, fun(), fun(), + verify_peer | verify_none, {fun(), term}, client | server) -> {der_cert(), public_key_info()} | #alert{}. %% %% Description: Handles a certificate handshake message %%-------------------------------------------------------------------- -certify(#certificate{asn1_certificates = ASN1Certs}, CertDbRef, - MaxPathLen, Verify, VerifyFun, ValidateFun, Role) -> +certify(#certificate{asn1_certificates = ASN1Certs}, CertDbRef, + MaxPathLen, _Verify, VerifyFunAndState, Role) -> [PeerCert | _] = ASN1Certs, - VerifyBool = verify_bool(Verify), - ValidateExtensionFun = - case ValidateFun of + ValidationFunAndState = + case VerifyFunAndState of undefined -> - fun(Extensions, ValidationState, Verify0, AccError) -> - ssl_certificate:validate_extensions(Extensions, ValidationState, - [], Verify0, AccError, Role) - end; - Fun -> - fun(Extensions, ValidationState, Verify0, AccError) -> - {NewExtensions, NewValidationState, NewAccError} - = ssl_certificate:validate_extensions(Extensions, ValidationState, - [], Verify0, AccError, Role), - Fun(NewExtensions, NewValidationState, Verify0, NewAccError) - end + {fun(OtpCert, ExtensionOrError, SslState) -> + ssl_certificate:validate_extension(OtpCert, + ExtensionOrError, SslState) + end, Role}; + {Fun, UserState0} -> + {fun(OtpCert, ExtensionOrError, {SslState, UserState}) -> + case ssl_certificate:validate_extension(OtpCert, + ExtensionOrError, + SslState) of + {valid, _} -> + apply_user_fun(Fun, OtpCert, + ExtensionOrError, UserState, + SslState); + {fail, Reason} -> + apply_user_fun(Fun, OtpCert, Reason, UserState, + SslState); + {unknown, _} -> + apply_user_fun(Fun, OtpCert, + ExtensionOrError, UserState, SslState) + end + end, {Role, UserState0}} end, - try - ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbRef) of - {TrustedErlCert, CertPath} -> - Result = public_key:pkix_path_validation(TrustedErlCert, - CertPath, - [{max_path_length, - MaxPathLen}, - {verify, VerifyBool}, - {validate_extensions_fun, - ValidateExtensionFun}]), - case Result of - {error, Reason} -> - path_validation_alert(Reason, Verify); - {ok, {PublicKeyInfo,_, []}} -> - {PeerCert, PublicKeyInfo}; - {ok, {PublicKeyInfo,_, AccErrors = [Error | _]}} -> - case VerifyFun(AccErrors) of - true -> - {PeerCert, PublicKeyInfo}; - false -> - path_validation_alert(Error, Verify) - end - end - catch - throw:Alert -> - Alert + + {TrustedErlCert, CertPath} = + ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbRef), + + case public_key:pkix_path_validation(TrustedErlCert, + CertPath, + [{max_path_length, + MaxPathLen}, + {verify_fun, ValidationFunAndState}]) of + {ok, {PublicKeyInfo,_}} -> + {PeerCert, PublicKeyInfo}; + {error, Reason} -> + path_validation_alert(Reason) end. - + %%-------------------------------------------------------------------- -spec certificate(der_cert(), term(), client | server) -> #certificate{} | #alert{}. %% @@ -490,26 +484,21 @@ get_tls_handshake_aux(<<?BYTE(Type), ?UINT24(Length), get_tls_handshake_aux(Data, Acc) -> {lists:reverse(Acc), Data}. -verify_bool(verify_peer) -> - true; -verify_bool(verify_none) -> - false. - -path_validation_alert({bad_cert, cert_expired}, _) -> +path_validation_alert({bad_cert, cert_expired}) -> ?ALERT_REC(?FATAL, ?CERTIFICATE_EXPIRED); -path_validation_alert({bad_cert, invalid_issuer}, _) -> +path_validation_alert({bad_cert, invalid_issuer}) -> ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE); -path_validation_alert({bad_cert, invalid_signature} , _) -> +path_validation_alert({bad_cert, invalid_signature}) -> ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE); -path_validation_alert({bad_cert, name_not_permitted}, _) -> +path_validation_alert({bad_cert, name_not_permitted}) -> ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE); -path_validation_alert({bad_cert, unknown_critical_extension}, _) -> +path_validation_alert({bad_cert, unknown_critical_extension}) -> ?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE); -path_validation_alert({bad_cert, cert_revoked}, _) -> +path_validation_alert({bad_cert, cert_revoked}) -> ?ALERT_REC(?FATAL, ?CERTIFICATE_REVOKED); -path_validation_alert({bad_cert, unknown_ca}, _) -> +path_validation_alert({bad_cert, unknown_ca}) -> ?ALERT_REC(?FATAL, ?UNKNOWN_CA); -path_validation_alert(_, _) -> +path_validation_alert(_) -> ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE). select_session(Hello, Port, Session, Version, @@ -1132,3 +1121,13 @@ key_exchange_alg(Alg) when Alg == dhe_rsa; Alg == dhe_dss; ?KEY_EXCHANGE_DIFFIE_HELLMAN; key_exchange_alg(_) -> ?NULL. + +apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState) -> + case Fun(OtpCert, ExtensionOrError, UserState0) of + {valid, UserState} -> + {valid, {SslState, UserState}}; + {fail, _} = Fail -> + Fail; + {unknown, UserState} -> + {unknown, {SslState, UserState}} + end. diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl index 337403531e..ddb05e70f6 100644 --- a/lib/ssl/src/ssl_internal.hrl +++ b/lib/ssl/src/ssl_internal.hrl @@ -63,10 +63,13 @@ validate_extensions_fun, depth, % integer() certfile, % file() + cert, % der_encoded() keyfile, % file() - key, % + key, % der_encoded() password, % + cacerts, % [der_encoded()] cacertfile, % file() + dh, % der_encoded() dhfile, % file() ciphers, % %% Local policy for the server if it want's to reuse the session diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index 459dcefb79..0116466677 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -69,12 +69,12 @@ start_link(Opts) -> gen_server:start_link({local, ?MODULE}, ?MODULE, [Opts], []). %%-------------------------------------------------------------------- --spec connection_init(string(), client | server) -> {ok, reference(), cache_ref()}. +-spec connection_init(string()| {der, list()}, client | server) -> {ok, reference(), cache_ref()}. %% %% Description: Do necessary initializations for a new connection. %%-------------------------------------------------------------------- -connection_init(TrustedcertsFile, Role) -> - call({connection_init, TrustedcertsFile, Role}). +connection_init(Trustedcerts, Role) -> + call({connection_init, Trustedcerts, Role}). %%-------------------------------------------------------------------- -spec cache_pem_file(string()) -> {ok, term()}. %% @@ -185,13 +185,13 @@ handle_call({{connection_init, "", _Role}, Pid}, _From, Result = {ok, make_ref(), Cache}, {reply, Result, State}; -handle_call({{connection_init, TrustedcertsFile, _Role}, Pid}, _From, +handle_call({{connection_init, Trustedcerts, _Role}, Pid}, _From, #state{certificate_db = Db, session_cache = Cache} = State) -> erlang:monitor(process, Pid), Result = try - {ok, Ref} = ssl_certificate_db:add_trusted_certs(Pid, TrustedcertsFile, Db), + {ok, Ref} = ssl_certificate_db:add_trusted_certs(Pid, Trustedcerts, Db), {ok, Ref, Cache} catch _:Reason -> diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl index 6db13e5b7a..25e7445180 100644 --- a/lib/ssl/src/ssl_session.erl +++ b/lib/ssl/src/ssl_session.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% Copyright Ericsson AB 2007-2010. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -113,7 +113,7 @@ select_session(Sessions, #ssl_options{ciphers = Ciphers, List -> hd(List) end. - + %% If we can not generate a not allready in use session ID in %% ?GEN_UNIQUE_ID_MAX_TRIES we make the new session uncacheable The %% value of ?GEN_UNIQUE_ID_MAX_TRIES is stolen from open SSL which diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index d50b34b6ac..1e96880801 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -232,10 +232,11 @@ all(suite) -> server_renegotiate, client_renegotiate_reused_session, server_renegotiate_reused_session, client_no_wrap_sequence_number, server_no_wrap_sequence_number, extended_key_usage, - validate_extensions_fun, no_authority_key_identifier, + no_authority_key_identifier, invalid_signature_client, invalid_signature_server, cert_expired, client_with_cert_cipher_suites_handshake, unknown_server_ca_fail, - unknown_server_ca_accept + der_input, unknown_server_ca_accept_verify_none, unknown_server_ca_accept_verify_peer, + unknown_server_ca_accept_backwardscompatibilty ]. %% Test cases starts here. @@ -1260,7 +1261,6 @@ eoptions(Config) when is_list(Config) -> {verify_fun, function}, {fail_if_no_peer_cert, 0}, {verify_client_once, 1}, - {validate_extensions_fun, function}, {depth, four}, {certfile, 'cert.pem'}, {keyfile,'key.pem' }, @@ -2271,14 +2271,7 @@ client_verify_none_active_once(Config) when is_list(Config) -> {mfa, {?MODULE, send_recv_result_active_once, []}}, {options, [{active, once} | ServerOpts]}]), Port = ssl_test_lib:inet_port(Server), - %% TODO: send message to test process to make sure - %% verifyfun has beeen run as it has the same behavior as - %% the default fun - VerifyFun = fun([{bad_cert, unknown_ca}]) -> - true; - (_) -> - false - end, + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, @@ -2286,8 +2279,7 @@ client_verify_none_active_once(Config) when is_list(Config) -> send_recv_result_active_once, []}}, {options, [{active, once}, - {verify, verify_none}, - {verify_fun, VerifyFun} + {verify, verify_none} | ClientOpts]}]), ssl_test_lib:check_result(Server, ok, Client, ok), @@ -2578,41 +2570,6 @@ extended_key_usage(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -validate_extensions_fun(doc) -> - ["Test that it is possible to specify a validate_extensions_fun"]; - -validate_extensions_fun(suite) -> - []; - -validate_extensions_fun(Config) when is_list(Config) -> - ClientOpts = ?config(client_verification_opts, Config), - ServerOpts = ?config(server_verification_opts, Config), - - Fun = fun(Extensions, State, _, AccError) -> - {Extensions, State, AccError} - end, - - {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - - Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options, [{validate_extensions_fun, Fun}, - {verify, verify_peer} | ServerOpts]}]), - Port = ssl_test_lib:inet_port(Server), - - Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {mfa, {?MODULE, send_recv_result_active, []}}, - {options,[{validate_extensions_fun, Fun} | ClientOpts]}]), - - ssl_test_lib:check_result(Server, ok, Client, ok), - - ssl_test_lib:close(Server), - ssl_test_lib:close(Client). - -%%-------------------------------------------------------------------- no_authority_key_identifier(doc) -> ["Test cert that does not have authorityKeyIdentifier extension" " but are present in trusted certs db."]; @@ -2749,7 +2706,7 @@ invalid_signature_client(Config) when is_list(Config) -> tcp_delivery_workaround(Server, {error, "bad certificate"}, Client, {error,"bad certificate"}). -tcp_delivery_workaround(Server, ServMsg, Client, ClientMsg) -> +tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) -> receive {Server, ServerMsg} -> receive @@ -2899,24 +2856,34 @@ unknown_server_ca_fail(Config) when is_list(Config) -> no_result, []}}, {options, ServerOpts}]), Port = ssl_test_lib:inet_port(Server), + + FunAndState = {fun(_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState} + end, []}, + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, {host, Hostname}, {from, self()}, {mfa, {ssl_test_lib, no_result, []}}, {options, - [{verify, verify_peer}| ClientOpts]}]), + [{verify, verify_peer}, + {verify_fun, FunAndState} + | ClientOpts]}]), - ssl_test_lib:check_result(Server, {error,"unknown ca"}, Client, {error, "unknown ca"}), + ssl_test_lib:check_result(Server, {error,"unknown ca"}, + Client, {error, "unknown ca"}), ssl_test_lib:close(Server), ssl_test_lib:close(Client). %%-------------------------------------------------------------------- -unknown_server_ca_accept(doc) -> +unknown_server_ca_accept_verify_none(doc) -> ["Test that the client succeds if the ca is unknown in verify_none mode"]; -unknown_server_ca_accept(suite) -> +unknown_server_ca_accept_verify_none(suite) -> []; -unknown_server_ca_accept(Config) when is_list(Config) -> +unknown_server_ca_accept_verify_none(Config) when is_list(Config) -> ClientOpts = ?config(client_opts, Config), ServerOpts = ?config(server_opts, Config), {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), @@ -2937,6 +2904,137 @@ unknown_server_ca_accept(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). +%%-------------------------------------------------------------------- +unknown_server_ca_accept_verify_peer(doc) -> + ["Test that the client succeds if the ca is unknown in verify_peer mode" + " with a verify_fun that accepts the unknown ca error"]; +unknown_server_ca_accept_verify_peer(suite) -> + []; +unknown_server_ca_accept_verify_peer(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + FunAndState = {fun(_,{bad_cert, unknown_ca}, UserState) -> + {valid, UserState}; + (_,{bad_cert, _} = Reason, _) -> + {fail, Reason}; + (_,{extension, _}, UserState) -> + {unknown, UserState} + end, []}, + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + send_recv_result_active, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, FunAndState}| ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +unknown_server_ca_accept_backwardscompatibilty(doc) -> + ["Test that the client succeds if the ca is unknown in verify_none mode"]; +unknown_server_ca_accept_backwardscompatibilty(suite) -> + []; +unknown_server_ca_accept_backwardscompatibilty(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, + send_recv_result_active, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + AcceptBadCa = fun({bad_cert,unknown_ca}, Acc) -> Acc; + (Other, Acc) -> [Other | Acc] + end, + VerifyFun = + fun(ErrorList) -> + case lists:foldl(AcceptBadCa, [], ErrorList) of + [] -> true; + [_|_] -> false + end + end, + + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, + send_recv_result_active, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, VerifyFun}| ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +der_input(doc) -> + ["Test to input certs and key as der"]; + +der_input(suite) -> + []; + +der_input(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + DHParamFile = filename:join(DataDir, "dHParam.pem"), + + SeverVerifyOpts = ?config(server_verification_opts, Config), + {ServerCert, ServerKey, ServerCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} | + SeverVerifyOpts]), + ClientVerifyOpts = ?config(client_verification_opts, Config), + {ClientCert, ClientKey, ClientCaCerts, DHParams} = der_input_opts([{dhfile, DHParamFile} | + ClientVerifyOpts]), + ServerOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}, + {dh, DHParams}, + {cert, ServerCert}, {key, ServerKey}, {cacerts, ServerCaCerts}], + ClientOpts = [{verify, verify_peer}, {fail_if_no_peer_cert, true}, + {dh, DHParams}, + {cert, ClientCert}, {key, ClientKey}, {cacerts, ClientCaCerts}], + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, send_recv_result, []}}, + {options, [{active, false} | ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, send_recv_result, []}}, + {options, [{active, false} | ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + +der_input_opts(Opts) -> + Certfile = proplists:get_value(certfile, Opts), + CaCertsfile = proplists:get_value(cacertfile, Opts), + Keyfile = proplists:get_value(keyfile, Opts), + Dhfile = proplists:get_value(dhfile, Opts), + [{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile), + [{_, Key, _}] = ssl_test_lib:pem_to_der(Keyfile), + [{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile), + CaCerts = + lists:map(fun(Entry) -> + {_, CaCert, _} = Entry, + CaCert + end, ssl_test_lib:pem_to_der(CaCertsfile)), + {Cert, {rsa, Key}, CaCerts, DHParams}. %%-------------------------------------------------------------------- %%% Internal functions diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl index 1e7cde1c25..88d2d99ef8 100644 --- a/lib/ssl/test/ssl_packet_SUITE.erl +++ b/lib/ssl/test/ssl_packet_SUITE.erl @@ -149,6 +149,7 @@ all(suite) -> packet_http_decode, packet_http_decode_list, packet_http_bin_decode_multi, + packet_http_error_passive, packet_line_decode, packet_line_decode_list, packet_asn1_decode, @@ -1737,6 +1738,71 @@ client_http_bin_decode(Socket, HttpRequest, Count) when Count > 0 -> client_http_bin_decode(Socket, HttpRequest, Count - 1); client_http_bin_decode(_, _, _) -> ok. + +%%-------------------------------------------------------------------- +packet_http_error_passive(doc) -> + ["Test setting the packet option {packet, http}, {active, false}" + " with a incorrect http header." ]; +packet_http_error_passive(suite) -> + []; +packet_http_error_passive(Config) when is_list(Config) -> + ClientOpts = ?config(client_opts, Config), + ServerOpts = ?config(server_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Request = "GET / HTTP/1.1\r\n" + "host: www.example.com\r\n" + "user-agent HttpTester\r\n" + "\r\n", + Response = "HTTP/1.1 200 OK\r\n" + "\r\n" + "Hello!", + + Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0}, + {from, self()}, + {mfa, {?MODULE, server_http_decode_error, + [Response]}}, + {options, [{active, false}, binary, + {packet, http} | + ServerOpts]}]), + + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {?MODULE, client_http_decode_list, + [Request]}}, + {options, [{active, true}, list, + {packet, http} | + ClientOpts]}]), + + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client). + + +server_http_decode_error(Socket, HttpResponse) -> + assert_packet_opt(Socket, http), + + {ok, {http_request, 'GET', _, {1,1}}} = ssl:recv(Socket, 0), + + assert_packet_opt(Socket, http), + + {ok, {http_header, _, 'Host', _, "www.example.com"}} = ssl:recv(Socket, 0), + assert_packet_opt(Socket, http), + + {ok, {http_error, _}} = ssl:recv(Socket, 0), + + assert_packet_opt(Socket, http), + + {ok, http_eoh} = ssl:recv(Socket, 0), + + assert_packet_opt(Socket, http), + ok = ssl:send(Socket, HttpResponse), + ok. + + %%-------------------------------------------------------------------- packet_line_decode(doc) -> ["Test setting the packet option {packet, line}, {mode, binary}"]; diff --git a/lib/stdlib/doc/src/erl_id_trans.xml b/lib/stdlib/doc/src/erl_id_trans.xml index 7c821d2efc..cfb18ec131 100644 --- a/lib/stdlib/doc/src/erl_id_trans.xml +++ b/lib/stdlib/doc/src/erl_id_trans.xml @@ -5,7 +5,7 @@ <header> <copyright> <year>1996</year> - <year>2007</year> + <year>2010</year> <holder>Ericsson AB, All Rights Reserved</holder> </copyright> <legalnotice> @@ -70,7 +70,8 @@ <section> <title>See Also</title> - <p><seealso marker="erl_parse">erl_parse(3)</seealso>, compile(3).</p> + <p><seealso marker="erl_parse">erl_parse(3)</seealso>, + <seealso marker="compiler:compile">compile(3)</seealso>.</p> </section> </erlref> diff --git a/lib/stdlib/doc/src/erl_lint.xml b/lib/stdlib/doc/src/erl_lint.xml index 6a7d37765c..8639d678fa 100644 --- a/lib/stdlib/doc/src/erl_lint.xml +++ b/lib/stdlib/doc/src/erl_lint.xml @@ -96,8 +96,8 @@ <p>The <c>AbsForms</c> of a module which comes from a file that is read through <c>epp</c>, the Erlang pre-processor, can come from many files. This means that any references to - errors must include the file name (see <seealso marker="epp">epp(3)</seealso>, or parser <seealso marker="erl_parse">erl_parse(3)</seealso> The warnings and - errors returned have the following format: + errors must include the file name (see <seealso marker="epp">epp(3)</seealso>, or parser <seealso marker="erl_parse">erl_parse(3)</seealso>). + The warnings and errors returned have the following format: </p> <code type="none"> [{FileName2,[ErrorInfo]}] </code> diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml index ae8a8afd5c..18b592deea 100644 --- a/lib/stdlib/doc/src/erl_parse.xml +++ b/lib/stdlib/doc/src/erl_parse.xml @@ -39,7 +39,7 @@ expressions, or terms. The Abstract Format is described in the ERTS User's Guide. Note that a token list must end with the <em>dot</em> token in order - to be acceptable to the parse functions (see erl_scan).</p> + to be acceptable to the parse functions (see <seealso marker="erl_scan">erl_scan(3)</seealso>).</p> </description> <funcs> <func> diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml index b3ad7aaf46..92c4eb4f4c 100644 --- a/lib/stdlib/doc/src/lists.xml +++ b/lib/stdlib/doc/src/lists.xml @@ -220,7 +220,7 @@ follows:</p> <code type="none"> flatmap(Fun, List1) -> - append(map(Fun, List1))</code> + append(map(Fun, List1)).</code> <p>Example:</p> <pre> > <input>lists:flatmap(fun(X)->[X,X] end, [a,b,c]).</input> @@ -523,7 +523,7 @@ flatmap(Fun, List1) -> <v> A = B = term()</v> </type> <desc> - <p><c>mapfold</c> combines the operations of <c>map/2</c> and + <p><c>mapfoldl</c> combines the operations of <c>map/2</c> and <c>foldl/3</c> into one pass. An example, summing the elements in a list and double them at the same time:</p> <pre> @@ -543,7 +543,7 @@ flatmap(Fun, List1) -> <v> A = B = term()</v> </type> <desc> - <p><c>mapfold</c> combines the operations of <c>map/2</c> and + <p><c>mapfoldr</c> combines the operations of <c>map/2</c> and <c>foldr/3</c> into one pass.</p> </desc> </func> diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml index 10ead62073..8cbfb9387b 100644 --- a/lib/stdlib/doc/src/sys.xml +++ b/lib/stdlib/doc/src/sys.xml @@ -34,7 +34,7 @@ <module>sys</module> <modulesummary>A Functional Interface to System Messages</modulesummary> <description> - <p>This module contains functions for sending system messages used by programs, and messaged used for debugging purposes. + <p>This module contains functions for sending system messages used by programs, and messages used for debugging purposes. </p> <p>Functions used for implementation of processes should also understand system messages such as debugging diff --git a/lib/test_server/src/Makefile b/lib/test_server/src/Makefile index d55a3a597d..3dca55178d 100644 --- a/lib/test_server/src/Makefile +++ b/lib/test_server/src/Makefile @@ -139,7 +139,7 @@ release_tests_spec: opt $(TARGET_FILES) $(TS_TARGET_FILES) \ $(AUTOCONF_FILES) $(C_FILES) $(COVER_FILES) $(CONFIG) \ $(RELEASE_PATH)/test_server - $(INSTALL_PROGRAM) $(PROGRAMS) $(RELEASE_PATH)/test_server + $(INSTALL_SCRIPT) $(PROGRAMS) $(RELEASE_PATH)/test_server release_docs_spec: diff --git a/lib/test_server/test/Makefile b/lib/test_server/test/Makefile index 702d73f5af..fcb1282d16 100644 --- a/lib/test_server/test/Makefile +++ b/lib/test_server/test/Makefile @@ -88,7 +88,7 @@ release_spec: opt release_tests_spec: make_emakefile $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(COVERFILE) $(RELSYSDIR) - $(INSTALL_PROGRAM) test_server.spec $(RELSYSDIR) + $(INSTALL_DATA) test_server.spec $(RELSYSDIR) chmod -f -R u+w $(RELSYSDIR) @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) diff --git a/lib/tools/doc/src/erlang_mode.xml b/lib/tools/doc/src/erlang_mode.xml index 912c442153..c21afc1f9b 100644 --- a/lib/tools/doc/src/erlang_mode.xml +++ b/lib/tools/doc/src/erlang_mode.xml @@ -173,7 +173,7 @@ sum(L) -> sum(L, 0). sum([H|T], Sum) -> sum(T, Sum + H); - sum([], Sum) -> Sum."</code> + sum([], Sum) -> Sum.</code> </item> </list> </section> diff --git a/lib/tools/doc/src/erlang_mode_chapter.xml b/lib/tools/doc/src/erlang_mode_chapter.xml index b22c6b1809..8aabd6ae74 100644 --- a/lib/tools/doc/src/erlang_mode_chapter.xml +++ b/lib/tools/doc/src/erlang_mode_chapter.xml @@ -45,7 +45,7 @@ <section> <title>Elisp</title> - <p>There are two Elsip modules include in this tool package + <p>There are two Elisp modules included in this tool package for Emacs. There is erlang.el that defines the actual erlang mode and there is erlang-start.el that makes some nice initializations.</p> </section> diff --git a/lib/wx/test/Makefile b/lib/wx/test/Makefile index 71b79aa272..dfec4bb695 100644 --- a/lib/wx/test/Makefile +++ b/lib/wx/test/Makefile @@ -63,7 +63,7 @@ release_spec: release_tests_spec: opt $(INSTALL_DIR) $(RELSYSDIR) $(INSTALL_DATA) wx.spec wx_test_lib.hrl $(ErlSrc) $(ErlTargets) $(RELSYSDIR) - $(INSTALL_PROGRAM) wxt $(RELSYSDIR) + $(INSTALL_SCRIPT) wxt $(RELSYSDIR) release_docs_spec: diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl index 4e5cc59d8f..e2e6f95c4a 100644 --- a/lib/xmerl/src/xmerl_scan.erl +++ b/lib/xmerl/src/xmerl_scan.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2003-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in %% compliance with the License. You should have received a copy of the %% Erlang Public License along with this software. If not, it can be %% retrieved online at http://www.erlang.org/. -%% +%% %% Software distributed under the License is distributed on an "AS IS" %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See %% the License for the specific language governing rights and limitations %% under the License. -%% +%% %% %CopyrightEnd% %% @@ -2602,8 +2602,7 @@ scan_reference("#x" ++ T, S0) -> %% [66] CharRef ?bump_col(1), if hd(T) /= $; -> - {[Ch], T2, S2} = scan_char_ref_hex(T, S, 0), - {to_char_set(S2#xmerl_scanner.encoding,Ch),T2,S2}; + scan_char_ref_hex(T, S, 0); true -> ?fatal(invalid_char_ref, S) end; @@ -3452,14 +3451,14 @@ scan_entity_value("%" ++ T, S0, Delim, Acc, PEName,Namespace,PENesting) -> %% {system,URI} or {public,URI} %% Included in literal. {ExpRef,Sx}=fetch_not_parse(Tuple,S1), - {EntV,_,_S2} = - scan_entity_value(ExpRef, Sx, no_delim,[], + {EntV, _, S5} = + scan_entity_value(ExpRef, Sx, no_delim,[], PERefName,parameter,[]), %% should do an update Write(parameter_entity) %% so next expand_pe_reference is faster - {EntV,_S2}; + {string_to_char_set(S5#xmerl_scanner.encoding, EntV), S5}; ExpRef -> - {ExpRef,S1} + {string_to_char_set(S1#xmerl_scanner.encoding, ExpRef) ,S1} end, %% single or duoble qoutes are not treated as delimeters %% in passages "included in literal" @@ -4020,12 +4019,12 @@ utf8_2_ucs([A|Rest]) when A < 16#80 -> utf8_2_ucs([A|Rest]) -> {{error,{bad_character,A}},Rest}. -to_char_set("iso-10646-utf-1",Ch) -> - [Ch]; -to_char_set(UTF8,Ch) when UTF8 =:= "utf-8"; UTF8 =:= undefined -> - ucs_2_utf8(Ch); -to_char_set(_,Ch) -> - [Ch]. +%% to_char_set("iso-10646-utf-1",Ch) -> +%% [Ch]; +%% to_char_set(UTF8,Ch) when UTF8 =:= "utf-8"; UTF8 =:= undefined -> +%% ucs_2_utf8(Ch); +%% to_char_set(_,Ch) -> +%% [Ch]. ucs_2_utf8(Ch) when Ch < 128 -> %% 0vvvvvvv |