1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 2005-2012. All Rights Reserved.
    5: %%
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %%
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %%
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: %%%-------------------------------------------------------------------
   21: %%% File    : erl_print_SUITE.erl
   22: %%% Author  : Rickard Green <rickard.s.green@ericsson.com>
   23: %%% Description : 
   24: %%%
   25: %%% Created : 10 Mar 2005 by Rickard Green <rickard.s.green@ericsson.com>
   26: %%%-------------------------------------------------------------------
   27: -module(erl_print_SUITE).
   28: -author('rickard.s.green@ericsson.com').
   29: 
   30: 
   31: %-define(line_trace, 1).
   32: 
   33: -define(DEFAULT_TIMEOUT, ?t:minutes(10)).
   34: 
   35: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   36: 	 init_per_group/2,end_per_group/2, 
   37: 	 init_per_testcase/2, end_per_testcase/2]).
   38: 
   39: -export([erlang_display/1, integer/1, float/1, 
   40: 	 string/1, character/1, snprintf/1, quote/1]).
   41: 
   42: -include_lib("test_server/include/test_server.hrl").
   43: 
   44: suite() -> [{ct_hooks,[ts_install_cth]}].
   45: 
   46: all() -> 
   47:     test_cases().
   48: 
   49: groups() -> 
   50:     [].
   51: 
   52: init_per_suite(Config) ->
   53:     Config.
   54: 
   55: end_per_suite(_Config) ->
   56:     ok.
   57: 
   58: init_per_group(_GroupName, Config) ->
   59:     Config.
   60: 
   61: end_per_group(_GroupName, Config) ->
   62:     Config.
   63: 
   64: 
   65: %%
   66: %%
   67: %% Test cases
   68: %%
   69: %%
   70: 
   71: test_cases() -> 
   72:     [erlang_display, integer, float, string, character,
   73:      snprintf, quote].
   74: 
   75: erlang_display(doc) -> [];
   76: erlang_display(suite) -> [];
   77: erlang_display(Config) when is_list(Config) ->
   78:     ?line put(erlang_display_test, ok),
   79:     OAIS = erts_debug:set_internal_state(available_internal_state, true),
   80: 
   81:     %% atoms
   82:     ?line chk_display(atom, "atom"),
   83:     ?line chk_display(true, "true"),
   84:     ?line chk_display(false, "false"),
   85:     ?line chk_display('DOWN', "'DOWN'"),
   86:     ?line chk_display('EXIT', "'EXIT'"),
   87:     ?line chk_display('asdDofw $@{}][', "'asdDofw $@{}]['"),
   88: 
   89:     %% integers
   90:     ?line chk_display(0, "0"),
   91:     ?line chk_display(1, "1"),
   92:     ?line chk_display(4711, "4711"),
   93:     ?line chk_display(((1 bsl 27) - 1), "134217727"),
   94:     ?line chk_display((1 bsl 27), "134217728"),
   95:     ?line chk_display((1 bsl 32), "4294967296"),
   96:     ?line chk_display(11111111111, "11111111111"),
   97:     ?line chk_display((1 bsl 59) - 1, "576460752303423487"),
   98:     ?line chk_display(1 bsl 59, "576460752303423488"),
   99:     ?line chk_display(111111111111111111111, "111111111111111111111"),
  100:     ?line chk_display(123456789012345678901234567890,
  101: 		      "123456789012345678901234567890"),
  102:     ?line chk_display(1 bsl 10000, str_1_bsl_10000()),
  103:     ?line chk_display(-1, "-1"),
  104:     ?line chk_display(-4711, "-4711"),
  105:     ?line chk_display(-(1 bsl 27), "-134217728"),
  106:     ?line chk_display(-((1 bsl 27) + 1), "-134217729"),
  107:     ?line chk_display(-(1 bsl 32), "-4294967296"),
  108:     ?line chk_display(-11111111111, "-11111111111"),
  109:     ?line chk_display(-(1 bsl 59), "-576460752303423488"),
  110:     ?line chk_display(-((1 bsl 59) + 1), "-576460752303423489"),
  111:     ?line chk_display(-111111111111111111111, "-111111111111111111111"),
  112:     ?line chk_display(-123456789012345678901234567890,
  113: 		      "-123456789012345678901234567890"),
  114:     ?line chk_display(-(1 bsl 10000), [$- | str_1_bsl_10000()]),
  115: 
  116:     ?line MyCre = my_cre(),
  117: 
  118:     %% pids
  119:     ?line chk_display(mk_pid_xstr({node(), MyCre}, 4711, 42)),
  120:     ?line chk_display(mk_pid_xstr({node(), oth_cre(MyCre)}, 4711, 42)),
  121:     ?line chk_display(mk_pid_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711, 42)),
  122: 
  123:     ?line chk_display(mk_pid_xstr({a@b, MyCre}, 4711, 42)),
  124:     ?line chk_display(mk_pid_xstr({a@b, oth_cre(MyCre)}, 4711, 42)),
  125:     ?line chk_display(mk_pid_xstr({a@b, oth_cre(oth_cre(MyCre))}, 4711, 42)),
  126: 
  127:     %% ports
  128:     ?line chk_display(mk_port_xstr({node(), MyCre}, 4711)),
  129:     ?line chk_display(mk_port_xstr({node(), oth_cre(MyCre)}, 4711)),
  130:     ?line chk_display(mk_port_xstr({node(), oth_cre(oth_cre(MyCre))}, 4711)),
  131: 
  132:     ?line chk_display(mk_port_xstr({c@d, MyCre}, 4711)),
  133:     ?line chk_display(mk_port_xstr({c@d, oth_cre(MyCre)}, 4711)),
  134:     ?line chk_display(mk_port_xstr({c@d, oth_cre(oth_cre(MyCre))}, 4711)),
  135: 
  136:     %% refs
  137:     ?line chk_display(mk_ref_xstr({node(), MyCre}, [1,2,3])),
  138:     ?line chk_display(mk_ref_xstr({node(), oth_cre(MyCre)}, [1,2,3])),
  139:     ?line chk_display(mk_ref_xstr({node(), oth_cre(oth_cre(MyCre))}, [1,2,3])),
  140: 
  141:     ?line chk_display(mk_ref_xstr({e@f, MyCre},[1,2,3] )),
  142:     ?line chk_display(mk_ref_xstr({e@f, oth_cre(MyCre)}, [1,2,3])),
  143:     ?line chk_display(mk_ref_xstr({e@f, oth_cre(oth_cre(MyCre))}, [1,2,3])),
  144: 
  145:     %% Compund terms
  146:     ?line {Pid, PidStr} = mk_pid_xstr({x@y, oth_cre(MyCre)}, 4712, 41),
  147:     ?line {Port, PortStr} = mk_port_xstr({x@y, oth_cre(MyCre)}, 4712),
  148:     ?line {Ref, RefStr} = mk_ref_xstr({e@f, oth_cre(MyCre)}, [11,12,13]),
  149: 
  150:     ?line chk_display({atom,-4711,Ref,{"hej",[Pid,222222222222222222222222,Port,4711]}},
  151: 		      "{atom,-4711,"++RefStr++",{\"hej\",["++PidStr++",222222222222222222222222,"++PortStr++",4711]}}"),
  152:     ?line chk_display({{{{{{{{{{{{{{{{{{{{{{{hi}}}}}}}}}}}}}}}}}}}}}}},
  153: 		      "{{{{{{{{{{{{{{{{{{{{{{{hi}}}}}}}}}}}}}}}}}}}}}}}"),
  154:     ?line chk_display([[[[[[[[[[[[[[[[[[[[[[[yo]]]]]]]]]]]]]]]]]]]]]]],
  155: 		      "[[[[[[[[[[[[[[[[[[[[[[[yo]]]]]]]]]]]]]]]]]]]]]]]"),
  156:     ?line chk_display({[{[{[{[{[{[{[{[{[{[{[{[ii]}]}]}]}]}]}]}]}]}]}]}]},
  157: 		      "{[{[{[{[{[{[{[{[{[{[{[{[ii]}]}]}]}]}]}]}]}]}]}]}]}"),
  158:     ?line chk_display([], "[]"), % Not really a compound term :)
  159:     ?line chk_display([a|b], "[a|b]"),
  160:     ?line chk_display([a,b,c|z], "[a,b,c|z]"),
  161:     ?line chk_display([a,b,c], "[a,b,c]"),
  162:     ?line chk_display([Pid,Port,Ref],
  163: 		      "["++PidStr++","++PortStr++","++RefStr++"]"),
  164:     ?line chk_display("abcdefghijklmnopqrstuvwxyz",
  165: 		      "\"abcdefghijklmnopqrstuvwxyz\""),
  166:     ?line chk_display("ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  167: 		      "\"ABCDEFGHIJKLMNOPQRSTUVWXYZ\""),
  168:     ?line chk_display("H E J", "\"H E J\""),
  169:     ?line chk_display("asdDofw $@{}][", "\"asdDofw $@{}][\""),
  170:     
  171:     %%
  172:     %% TODO: Check binaries, fun and floats...
  173:     %%
  174: 
  175:     erts_debug:set_internal_state(available_internal_state, OAIS),
  176:     ?line ok = get(erlang_display_test).
  177: 
  178: get_chnl_no(NodeName) when is_atom(NodeName) ->
  179:     erts_debug:get_internal_state({channel_number, NodeName}).
  180: 
  181: chk_display(Term, Expect) when is_list(Expect) ->
  182:     Dstr = erts_debug:display(Term),
  183:     case Expect ++ io_lib:nl() of
  184: 	Dstr ->
  185: 	    ?t:format("Test of \"~p\" succeeded.~n"
  186: 		      "  Expected and got: ~s~n",
  187: 		      [Term, io_lib:write_string(Dstr)]);
  188: 	DoExpect ->
  189: 	    ?t:format("***~n"
  190: 		      "*** Test of \"~p\" failed!~n"
  191: 		      "***       Expected: ~s~n"
  192: 		      "***            Got: ~s~n"
  193: 		      "***~n",
  194: 		      [Term,
  195: 		       io_lib:write_string(DoExpect),
  196: 		       io_lib:write_string(Dstr)]),
  197: 	    put(erlang_display_test, failed)
  198:     end.
  199: 
  200: chk_display({Term, Expect}) ->
  201:     chk_display(Term, Expect).
  202: 
  203: mk_pid_xstr({NodeName, Creation}, Number, Serial) ->
  204:     Pid = mk_pid({NodeName, Creation}, Number, Serial),
  205:     XStr = "<" ++ integer_to_list(get_chnl_no(NodeName))
  206: 	++ "." ++ integer_to_list(Number)
  207: 	++ "." ++ integer_to_list(Serial) ++ ">",
  208:     {Pid, XStr}.
  209: 
  210: mk_port_xstr({NodeName, Creation}, Number) ->
  211:     Port = mk_port({NodeName, Creation}, Number),
  212:     XStr = "#Port<" ++ integer_to_list(get_chnl_no(NodeName))
  213: 	++ "." ++ integer_to_list(Number) ++ ">",
  214:     {Port, XStr}.
  215: 
  216: mk_ref_xstr({NodeName, Creation}, Numbers) ->
  217:     Ref = mk_ref({NodeName, Creation}, Numbers),
  218:     XStr = "#Ref<" ++ integer_to_list(get_chnl_no(NodeName))
  219: 	++ ref_numbers_xstr(Numbers) ++ ">",
  220:     {Ref, XStr}.
  221: 
  222: ref_numbers_xstr([]) ->
  223:     [];
  224: ref_numbers_xstr([N | Ns]) ->
  225:     ref_numbers_xstr(Ns) ++ "." ++ integer_to_list(N).
  226: 
  227: -define(TESTCASE_IMPL(T), T(A) -> default_testcase_impl(A)).
  228: 
  229: ?TESTCASE_IMPL(integer).
  230: ?TESTCASE_IMPL(float).
  231: ?TESTCASE_IMPL(string).
  232: ?TESTCASE_IMPL(character).
  233: ?TESTCASE_IMPL(snprintf).
  234: ?TESTCASE_IMPL(quote).
  235: 
  236: %%
  237: %%
  238: %% Auxiliary functions
  239: %%
  240: %%
  241: 
  242: default_testcase_impl(doc) -> [];
  243: default_testcase_impl(suite) -> [];
  244: default_testcase_impl(Config) when is_list(Config) -> ?line run_case(Config).
  245: 
  246: init_per_testcase(Case, Config) ->
  247:     Dog = ?t:timetrap(?DEFAULT_TIMEOUT),
  248:     [{testcase, Case}, {watchdog, Dog} |Config].
  249: 
  250: end_per_testcase(_Case, Config) ->
  251:     Dog = ?config(watchdog, Config),
  252:     ?t:timetrap_cancel(Dog),
  253:     ok.
  254: 
  255: -define(TESTPROG, "erl_print_tests").
  256: -define(FAILED_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$F,$A,$I,$L,$U,$R,$E).
  257: -define(SKIPPED_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$S,$K,$I,$P).
  258: -define(SUCCESS_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$S,$U,$C,$C,$E,$S,$S).
  259: -define(PID_MARKER, $E,$P,$-,$T,$E,$S,$T,$-,$P,$I,$D).
  260: 
  261: port_prog_killer(EProc, OSProc) when is_pid(EProc), is_list(OSProc) ->
  262:     ?line process_flag(trap_exit, true),
  263:     ?line Ref = erlang:monitor(process, EProc),
  264:     ?line receive
  265: 	      {'DOWN', Ref, _, _, Reason} when is_tuple(Reason),
  266: 					       element(1, Reason)
  267: 					       == timetrap_timeout ->
  268: 		  ?line Cmd = "kill -9 " ++ OSProc,
  269: 		  ?line ?t:format("Test case timed out. "
  270: 				  "Trying to kill port program.~n"
  271: 				  "  Executing: ~p~n", [Cmd]),
  272: 		  ?line case os:cmd(Cmd) of
  273: 			    [] ->
  274: 				ok;
  275: 			    OsCmdRes ->
  276: 				?line ?t:format("             ~s", [OsCmdRes])
  277: 			end;
  278: 	      {'DOWN', Ref, _, _, _} ->
  279: 		  %% OSProc is assumed to have terminated by itself
  280: 		  ?line ok 
  281: 	  end.
  282: 
  283: get_line(_Port, eol, Data) ->
  284:     ?line Data;
  285: get_line(Port, noeol, Data) ->
  286:     ?line receive
  287: 	      {Port, {data, {Flag, NextData}}} ->
  288: 		  ?line get_line(Port, Flag, Data ++ NextData);
  289: 	      {Port, eof} ->
  290: 		  ?line ?t:fail(port_prog_unexpectedly_closed)
  291: 	  end.
  292: 
  293: read_case_data(Port, TestCase) ->
  294:     ?line receive
  295: 	      {Port, {data, {eol, [?SUCCESS_MARKER]}}} ->
  296: 		  ?line ok;
  297: 	      {Port, {data, {Flag, [?SUCCESS_MARKER | CommentStart]}}} ->
  298: 		  ?line {comment, get_line(Port, Flag, CommentStart)};
  299: 	      {Port, {data, {Flag, [?SKIPPED_MARKER | CommentStart]}}} ->
  300: 		  ?line {skipped, get_line(Port, Flag, CommentStart)};
  301: 	      {Port, {data, {Flag, [?FAILED_MARKER | ReasonStart]}}} ->
  302: 		  ?line ?t:fail(get_line(Port, Flag, ReasonStart));
  303: 	      {Port, {data, {eol, [?PID_MARKER | PidStr]}}} ->
  304: 		  ?line ?t:format("Port program pid: ~s~n", [PidStr]),
  305: 		  ?line CaseProc = self(),
  306: 		  ?line _ = list_to_integer(PidStr), % Sanity check
  307: 		  spawn_opt(fun () ->
  308: 				    port_prog_killer(CaseProc, PidStr)
  309: 			    end,
  310: 			    [{priority, max}, link]),
  311: 		  read_case_data(Port, TestCase);
  312: 	      {Port, {data, {Flag, LineStart}}} ->
  313: 		  ?line ?t:format("~s~n", [get_line(Port, Flag, LineStart)]),
  314: 		  read_case_data(Port, TestCase);
  315: 	      {Port, eof} ->
  316: 		  ?line ?t:fail(port_prog_unexpectedly_closed)
  317: 	  end.
  318: 
  319: run_case(Config) ->
  320:     run_case(Config, "").
  321: 
  322: run_case(Config, TestArgs) ->
  323:     run_case(Config, TestArgs, fun (_Port) -> ok end).
  324: 
  325: run_case(Config, TestArgs, Fun) ->
  326:     Test = atom_to_list(?config(testcase, Config)),
  327:     TestProg = filename:join([?config(data_dir, Config),
  328: 			      ?TESTPROG
  329: 			      ++ "."
  330: 			      ++ atom_to_list(erlang:system_info(threads))]),
  331:     Cmd = TestProg ++ " " ++ Test ++ " " ++ TestArgs,
  332:     case catch open_port({spawn, Cmd}, [stream,
  333: 					use_stdio,
  334: 					stderr_to_stdout,
  335: 					eof,
  336: 					{line, 1024}]) of
  337: 	Port when is_port(Port) ->
  338: 	    ?line Fun(Port),
  339: 	    ?line CaseResult = read_case_data(Port, Test),
  340: 	    ?line receive
  341: 		      {Port, eof} ->
  342: 			  ?line ok
  343: 		  end,
  344: 	    ?line CaseResult;
  345: 	Error ->
  346: 	    ?line ?t:fail({open_port_failed, Error})
  347:     end.
  348: 
  349: 
  350: -define(VERSION_MAGIC,       131).
  351: 
  352: -define(ATOM_EXT,            100).
  353: -define(REFERENCE_EXT,       101).
  354: -define(PORT_EXT,            102).
  355: -define(PID_EXT,             103).
  356: -define(NEW_REFERENCE_EXT,   114).
  357: 
  358: uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 ->
  359:     [(Uint bsr 24) band 16#ff,
  360:      (Uint bsr 16) band 16#ff,
  361:      (Uint bsr 8) band 16#ff,
  362:      Uint band 16#ff];
  363: uint32_be(Uint) ->
  364:     exit({badarg, uint32_be, [Uint]}).
  365: 
  366: 
  367: uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 ->
  368:     [(Uint bsr 8) band 16#ff,
  369:      Uint band 16#ff];
  370: uint16_be(Uint) ->
  371:     exit({badarg, uint16_be, [Uint]}).
  372: 
  373: uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 ->
  374:     Uint band 16#ff;
  375: uint8(Uint) ->
  376:     exit({badarg, uint8, [Uint]}).
  377: 
  378: 
  379: 
  380: mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) ->
  381:     mk_pid({atom_to_list(NodeName), Creation}, Number, Serial);
  382: mk_pid({NodeName, Creation}, Number, Serial) ->
  383:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
  384: 					      ?PID_EXT,
  385: 					      ?ATOM_EXT,
  386: 					      uint16_be(length(NodeName)),
  387: 					      NodeName,
  388: 					      uint32_be(Number),
  389: 					      uint32_be(Serial),
  390: 					      uint8(Creation)])) of
  391: 	Pid when is_pid(Pid) ->
  392: 	    Pid;
  393: 	{'EXIT', {badarg, _}} ->
  394: 	    exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]});
  395: 	Other ->
  396: 	    exit({unexpected_binary_to_term_result, Other})
  397:     end.
  398: 
  399: mk_port({NodeName, Creation}, Number) when is_atom(NodeName) ->
  400:     mk_port({atom_to_list(NodeName), Creation}, Number);
  401: mk_port({NodeName, Creation}, Number) ->
  402:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
  403: 					      ?PORT_EXT,
  404: 					      ?ATOM_EXT,
  405: 					      uint16_be(length(NodeName)),
  406: 					      NodeName,
  407: 					      uint32_be(Number),
  408: 					      uint8(Creation)])) of
  409: 	Port when is_port(Port) ->
  410: 	    Port;
  411: 	{'EXIT', {badarg, _}} ->
  412: 	    exit({badarg, mk_port, [{NodeName, Creation}, Number]});
  413: 	Other ->
  414: 	    exit({unexpected_binary_to_term_result, Other})
  415:     end.
  416: 
  417: mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName),
  418: 					   is_integer(Creation),
  419: 					   is_list(Numbers) ->
  420:     mk_ref({atom_to_list(NodeName), Creation}, Numbers);
  421: mk_ref({NodeName, Creation}, [Number]) when is_list(NodeName),
  422: 					    is_integer(Creation),
  423: 					    is_integer(Number) ->
  424:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
  425: 					      ?REFERENCE_EXT,
  426: 					      ?ATOM_EXT,
  427: 					      uint16_be(length(NodeName)),
  428: 					      NodeName,
  429: 					      uint32_be(Number),
  430: 					      uint8(Creation)])) of
  431: 	Ref when is_reference(Ref) ->
  432: 	    Ref;
  433: 	{'EXIT', {badarg, _}} ->
  434: 	    exit({badarg, mk_ref, [{NodeName, Creation}, [Number]]});
  435: 	Other ->
  436: 	    exit({unexpected_binary_to_term_result, Other})
  437:     end;
  438: mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName),
  439: 					   is_integer(Creation),
  440: 					   is_list(Numbers) ->
  441:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
  442: 					      ?NEW_REFERENCE_EXT,
  443: 					      uint16_be(length(Numbers)),
  444: 					      ?ATOM_EXT,
  445: 					      uint16_be(length(NodeName)),
  446: 					      NodeName,
  447: 					      uint8(Creation),
  448: 					      lists:map(fun (N) ->
  449: 								uint32_be(N)
  450: 							end,
  451: 							Numbers)])) of
  452: 	Ref when is_reference(Ref) ->
  453: 	    Ref;
  454: 	{'EXIT', {badarg, _}} ->
  455: 	    exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]});
  456: 	Other ->
  457: 	    exit({unexpected_binary_to_term_result, Other})
  458:     end.
  459: 
  460: my_cre() -> erlang:system_info(creation).
  461: 
  462: oth_cre(0) -> 1;
  463: oth_cre(1) -> 2;
  464: oth_cre(2) -> 3;
  465: oth_cre(3) -> 1;
  466: oth_cre(N) -> exit({invalid_creation, N}).
  467: 
  468: str_1_bsl_10000() ->
  469:     "19950631168807583848837421626835850838234968318861924548520089498529438830221946631919961684036194597899331129423209124271556491349413781117593785932096323957855730046793794526765246551266059895520550086918193311542508608460618104685509074866089624888090489894838009253941633257850621568309473902556912388065225096643874441046759871626985453222868538161694315775629640762836880760732228535091641476183956381458969463899410840960536267821064621427333394036525565649530603142680234969400335934316651459297773279665775606172582031407994198179607378245683762280037302885487251900834464581454650557929601414833921615734588139257095379769119277800826957735674444123062018757836325502728323789270710373802866393031428133241401624195671690574061419654342324638801248856147305207431992259611796250130992860241708340807605932320161268492288496255841312844061536738951487114256315111089745514203313820202931640957596464756010405845841566072044962867016515061920631004186422275908670900574606417856951911456055068251250406007519842261898059237118054444788072906395242548339221982707404473162376760846613033778706039803413197133493654622700563169937455508241780972810983291314403571877524768509857276937926433221599399876886660808368837838027643282775172273657572744784112294389733810861607423253291974813120197604178281965697475898164531258434135959862784130128185406283476649088690521047580882615823961985770122407044330583075869039319604603404973156583208672105913300903752823415539745394397715257455290510212310947321610753474825740775273986348298498340756937955646638621874569499279016572103701364433135817214311791398222983845847334440270964182851005072927748364550578634501100852987812389473928699540834346158807043959118985815145779177143619698728131459483783202081474982171858011389071228250905826817436220577475921417653715687725614904582904992461028630081535583308130101987675856234343538955409175623400844887526162643568648833519463720377293240094456246923254350400678027273837755376406726898636241037491410966718557050759098100246789880178271925953381282421954028302759408448955014676668389697996886241636313376393903373455801407636741877711055384225739499110186468219696581651485130494222369947714763069155468217682876200362777257723781365331611196811280792669481887201298643660768551639860534602297871557517947385246369446923087894265948217008051120322365496288169035739121368338393591756418733850510970271613915439590991598154654417336311656936031122249937969999226781732358023111862644575299135758175008199839236284615249881088960232244362173771618086357015468484058622329792853875623486556440536962622018963571028812361567512543338303270029097668650568557157505516727518899194129711337690149916181315171544007728650573189557450920330185304847113818315407324053319038462084036421763703911550639789000742853672196280903477974533320468368795868580237952218629120080742819551317948157624448298518461509704888027274721574688131594750409732115080498190455803416826949787141316063210686391511681774304792596709376".