cvsuser     05/03/31 04:20:42

  Modified:    runtime/parrot/library/Digest MD5.imc
               t/library md5.t
  Log:
  - endian check is now done only once (at load time)
  - added _md5_hex, it returns the md5sum as string
  - 2 new tests
  
  Revision  Changes    Path
  1.3       +66 -28    parrot/runtime/parrot/library/Digest/MD5.imc
  
  Index: MD5.imc
  ===================================================================
  RCS file: /cvs/public/parrot/runtime/parrot/library/Digest/MD5.imc,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- MD5.imc   28 Mar 2005 12:21:59 -0000      1.2
  +++ MD5.imc   31 Mar 2005 12:20:39 -0000      1.3
  @@ -29,6 +29,10 @@
   
   Pass it the Integer array to print the checksum.
   
  +=head2 _md5_hex
  +
  +Pass it the Integer array to get the checksum as string.
  +
   =head1 BUGS
   
   Only tested so far on i386.
  @@ -47,11 +51,36 @@
   # export function entries to globals
   
   .sub onload @LOAD
  +    .local pmc endian
  +    endian = new Integer
  +    endian = 0
  +    store_global "Digest", "_md5_swap_endian", endian
  +    
  +    $P0 = _config()
  +
  +    $I0 = $P0["intsize"]
  +    if $I0 == 4 goto is_4byte_word
  +
  +    printerr "This doesn't seem to be a 32 bit processor: "
  +    printerr "Please verify the MD5 checksum\n"
  +
  +is_4byte_word:
  +
  +    $I0 = $P0["bigendian"]
  +    unless $I0 goto is_little_endian
  +    endian = 1
  +    printerr "This appears to be a big endian processor: "
  +    printerr "Please verify the MD5 checksum\n"
  +
  +is_little_endian:
  +
       .local pmc f
       f = find_global "Digest", "_md5sum"
       global "_md5sum" = f
       f = find_global "Digest", "_md5_print"
       global "_md5_print" = f
  +    f = find_global "Digest", "_md5_hex"
  +    global "_md5_hex" = f
   .end
   
   .include "library/config.imc"
  @@ -64,31 +93,15 @@
   .sub _md5sum
       .param string str
   
  -    $P0 = _config()
  -
  -    $I0 = $P0["intsize"]
  -    if $I0 == 4 goto is_4byte_word
  -
  -    printerr "This doesn't seem to be a 32 bit processor: "
  -    printerr "Please verify the MD5 checksum\n"
  -
  -is_4byte_word:
  -
  -    .local int endian
  -    endian = $P0["bigendian"]
  -    unless endian goto is_little_endian
  -    printerr "This appears to be a big endian processor: "
  -    printerr "Please verify the MD5 checksum\n"
  -
  -is_little_endian:
  -
       .local pmc buffer, context
       buffer = new FixedIntegerArray
   
       context = new FixedIntegerArray
       context = 4
   
  -    _md5_create_buffer (str, buffer, endian)
  +    $P0 = find_global "Digest", "_md5_swap_endian"
  +    $I0 = $P0
  +    _md5_create_buffer (str, buffer, $I0)
   
       # _print_buffer (buffer, 8)
   
  @@ -408,16 +421,17 @@
       context[2] = C
       context[3] = D
   
  -    # print_vals (A,B,C,D)
  +    # $S0 = _format_vals (A,B,C,D)
  +    # print $S0
       # print "\n"
   
   .end
   
   ###########################################################################
   
  -# Print four hex values
  +# format four hex values
   
  -.sub _print_vals
  +.sub _format_vals
       .param int A
       .param int B
       .param int C
  @@ -431,7 +445,7 @@
       $P0[3] = D
   
       sprintf $S0, "%08lx%08lx%08lx%08lx", $P0
  -    print $S0
  +    .return($S0)
   .end
   
   ###########################################################################
  @@ -451,11 +465,35 @@
       C = context[2]
       D = context[3]
   
  -    $P0 = _config()
  +    $P0 = find_global "Digest", "_md5_swap_endian"
  +    if $P0 goto dont_swap
   
  -    $I0 = $P0["bigendian"]
  +    .swap (A)
  +    .swap (B)
  +    .swap (C)
  +    .swap (D)
  +
  +dont_swap:
  +
  +    $S0 = _format_vals (A,B,C,D)
  +    print $S0
  +.end
  +
  +.sub _md5_hex
  +    .param pmc context
   
  -    if $I0 goto dont_swap
  +    .local int A
  +    .local int B
  +    .local int C
  +    .local int D
  +
  +    A = context[0]
  +    B = context[1]
  +    C = context[2]
  +    D = context[3]
  +
  +    $P0 = find_global "Digest", "_md5_swap_endian"
  +    if $P0 goto dont_swap
   
       .swap (A)
       .swap (B)
  @@ -464,8 +502,8 @@
   
   dont_swap:
   
  -    _print_vals (A,B,C,D)
  -
  +    $S0 = _format_vals (A,B,C,D)
  +    .return($S0)
   .end
   
   ###########################################################################
  
  
  
  1.3       +475 -1    parrot/t/library/md5.t
  
  Index: md5.t
  ===================================================================
  RCS file: /cvs/public/parrot/t/library/md5.t,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- md5.t     28 Mar 2005 12:22:00 -0000      1.2
  +++ md5.t     31 Mar 2005 12:20:42 -0000      1.3
  @@ -10,7 +10,7 @@
   # regressisions in the parrot VM, JIT and GC
   
   use strict;
  -use Parrot::Test tests => 4;
  +use Parrot::Test tests => 6;
   
   use Parrot::Config;
   
  @@ -336,3 +336,477 @@
   OUT
   
   }
  +
  +=bash
  +
  +test output created with:
  +
  +#!/bin/bash
  +str=$1
  +echo "$str"
  +for i in $(seq 1 200); do
  +    str=$(echo -n "$str" | md5sum | cut -d ' ' -f 1)
  +    echo "$str"
  +done
  +
  +=cut
  +
  +pir_output_is(<<'CODE', <<'OUT', "recursive md5sum (1)");
  +.sub _main
  +    load_bytecode "library/Digest/MD5.imc"
  +
  +    $S0 = "Hello World!"
  +    $I0 = 0
  +    
  +loop:
  +    print $S0
  +    print "\n"
  +    if $I0 >= 200 goto end
  +    $P0 = _md5sum($S0)
  +    $S0 = _md5_hex($P0)
  +    inc $I0
  +    branch loop
  +end:
  +    end
  +.end
  +CODE
  +Hello World!
  +ed076287532e86365e841e92bfc50d8c
  +153163e20c7dd03b131fe2bf21927e1e
  +95b9b73c7a8abe6d5bf5ad8067a53cee
  +d7b6778d149c5a085f2675b959503c2b
  +4a3dd453c637dabbdce7433653e6d7cb
  +88648d19a031133d87b093997813a740
  +a07578c3f0bebca3f2cca2b1d0b8f9fe
  +6134e6ee02e25ea0faf7a348ef599cdd
  +188ee3fb92bb86c91a08198100fa167a
  +dc06bc1fb41cae72a4b60e8480817085
  +c492befd605b7b05007d91db742600d3
  +2a07fa4fc4318d11908102c355ca81a8
  +6270c9b254b7c7c245100afb0778189f
  +31ca2cf9439c7f4f1da11a16a7bed6de
  +19626ef62b26446d35860ff932863894
  +3fe6e0f6adff71bc0a1a5b272527408d
  +3ef498d8ff923f1f91c0be6606da6dc1
  +34c5a11fc7d4a5ba70472f98e43c2f7b
  +7f0e1ffc3c4e3aa21bce804fd15cca1c
  +da76374e9095cdeb3bc95d3f9444f47e
  +f0dee836be39db7440b3c6ca4671afba
  +645a3f6129b1db41e986d94c7c6df03b
  +09300ce54fbae580ca496975bc3746af
  +65721cae6209d5ce50b17b06a9d693c8
  +b0038c2e9e9e01bf6883aaffc7726dec
  +18e9b196e808d2de844269b0608050d6
  +e563825454806b0ef84cf92fc9f54bfe
  +312f040493d0f7e4cc300bf70522e7bb
  +f4b2951c999e85a0db42799cfac9cca9
  +5dc63983b315585c8b68614c1837f358
  +ab577e59aa6a91d46f3f0bbe4f8f52a0
  +479b376dc5bc108efddb9139e3f48683
  +5fac17e1a48c1e1b3b8a696cc9f8992d
  +bef9fd06a052823abcfed2851cc2c505
  +09682b791db555c9867dc750eee0dd92
  +d9cb3599d16c4d197af9d1d54ad8fd0b
  +d9f1f852cf0dc85f3f676a492bfa6165
  +366d491706ad8ae5e726cedd3b08da77
  +a2849d41666406842463e406210df7da
  +63dc097352e3e637cc06b5682f781bd4
  +bc8ac884c97864f3d00d51240eeb06e6
  +7bc0f81018700689eecd45a4c70d4fae
  +33a71e77fd62d81d0cf6bda304606919
  +f32bd05330a93b0f95d88484908af7cd
  +8c4d905dd7fc8e965713f04841654cf4
  +33d7e3b19719f6b7386dae5bc2bfe881
  +069e844b1ef6230502f21ab8305fce67
  +801a4cfd4974f7267a8717faa7ec1dea
  +69d1a0fc4115f3f2e1e7db00c9d9cc10
  +79d62c23d99e920058aacfb3a71727c9
  +4386f8f55928bf946715d475caee6329
  +c2c9922ca2dae04985aa6488b87a7920
  +c0362fd0f999083411a34554901f8bb2
  +b6006163f03a93160879dcf4c930f769
  +6bc51c74e5a48f55dfdd6ec832c729c4
  +3f358f1893cfabdcd2020d8a1a2228d9
  +0d58c1a1dc62d768bfce37629c0f13c1
  +de66ee9f9d5373aa9ad259c8b3252909
  +c4e752f1a4c371ed24c4432941a5c2ea
  +778932a44e59ab759d8c5dc58f708242
  +54ce309ae9d4180a5a0adfee5dbc9c09
  +155a9f73f32ee6daf9c63e0051fdde6b
  +4025eb29c97dff3a44272b80b59963f4
  +7422ed91f76bf90e563c2002975632da
  +2a852d35bd49b7615321116725a32d0a
  +4b51d3d0f011b47d3f19e46dd1b525c6
  +62b3f84c8ad8762800efd35e67b02870
  +87483a3a842997956624542314accd89
  +d16383146ca5f31899d0d67f70e0395f
  +8beb021063ab267d37299fda68493ce7
  +7c2861c7d3318a11232ce920b14b13ad
  +1bf15129d5dfdf031921884175560813
  +b122b76f62757700c94f364cffef4cb5
  +89654021f6cec4d23a4c0f432d43eace
  +3f8021e428a41481b6454621eefec06d
  +44d7f6a4a01e1f06ae99751f9f82724f
  +07e7463bc04afb99ca64f65065954c90
  +c4c917cde83ed67e046cc3d88dbd662d
  +50dd647fe2f8daac51b1e9fd82cd0c59
  +6996c802026e01b31c2c5335ecbd189c
  +facb55614a088253f7f523d6d866e0f3
  +2be76a537c144f68b373a3994cd54c00
  +1a1a5b5acf50e98b1b9e8b918842b06e
  +0db736e817c45e4b653ed7f0c4e11962
  +5bf01fad828b838eeb1ff1274d876ccf
  +0fc2f4335bb190fa426abdb25de3da63
  +76b18e07cfdc6b293d91bdddbb61ec44
  +d0e138c4c80fa3915ba39b65512b799e
  +2144a5cb38bfc3691e3f8320e206aa5a
  +d11ec2aa70f7e58fc8f870d971352c79
  +17997c047bf5a2f401df7b908e47d2d1
  +85127ad7f64592b3e26cf0a1cdb2d890
  +5caaff4022e4f11f7f3e90d9974e2532
  +ab7193c2ed710ac8a0751b440e6448bc
  +6f2f2a3608de8fb79dc3309bd175e8e4
  +5a61579726264cc970497364cbbe191f
  +013c4f7a6b922542ea633f095b62fa6d
  +ce78937e0701406f642ebc3b9a29736b
  +e982e60d843c27b4858de896fcd075f9
  +8010f2cc72ba2554831348eebf6f8063
  +898ca64355754b2739b197a12f81e72b
  +b10bd7a27a36d90db7404079249a9f2a
  +cc673e2f9e08dd4a5da13931fb12f256
  +5a330e820ae46926566728f4abf6b87c
  +cbd0dd745c96ded00ff4627ea09bf97e
  +13a6d457cb091d0d9fe6deb410bc5d61
  +d7fa1c426850c9fee843f26b8c77c2d3
  +a604741ba924f4eafba8bd901b211f71
  +9299b0abdee549d55201efb3cc2fedde
  +f7a77b983776ec5eb3623476abffd222
  +9b276abb98aab4679006837318f9c64f
  +9c26edea8dc26d13e08a2cb4a4e4bd0f
  +56509b48041cf2de19f95688c53411af
  +bdf23fd1e120588501b012e7f58f2f4e
  +c588a957d5c8aded27a80e61c10e6723
  +88cd2ece9f5a8f40e20db49e2ee665cc
  +81088b08083648a6389a885791999f80
  +b45f5958a624def39c6bb1ac08c65605
  +01bd47325d69032df808d77304ddb250
  +3de24ffe65f69f32e2ffad7660f9da80
  +894a41dc061257bff5d1dc01f0c53288
  +52051634a70acb7576124d7a58a95109
  +75972f135bc8352457e20a3a90a6a589
  +c4a3008d30a7301cac9e9c62768fbed6
  +a965aa510d98ccd2727739e7e0ad9baf
  +fe789ea51ba9c2dfd89201957dbed4e8
  +ac65a4908d1453f02099da5fe395b874
  +dd97042c49e4d5e02543e6fec306dc1d
  +fdf60f998f585cc0077642fce8d968d8
  +686bc6f7a5ae6c0b24244514ba31bcb3
  +82e8a11f78293cdef3aed1b409cc4341
  +1cbb3fc50103062e3af258ca7fa76fef
  +e79344cd8e4889cd96aae999ac7f1d92
  +203e9fba5f417f6818ac5997dea57c36
  +62d2dfb64abd0e990edacb7dd380789c
  +b588fddddc8bdeacca65a3898ccc31c6
  +0de848c93df70d3f8b4536daedb965e7
  +cb672ab063522a764f14e9146d8b50f6
  +c5e2f087d25d0a32f14e9e30cd42b3e5
  +e81920116df890f329496f3374b2916a
  +2a03fcb63f2fdac03e4efa49607d1204
  +12fcc5b48205df7f6765200f134bed6b
  +54be0d792fb11d71511a39b0981b8855
  +f84aa178ad34aa06d9a1eb1560a51473
  +7e754096ec34c6255fbadd10cc99271c
  +d37e8a1c3ba5127e2f671f2af1b1c147
  +6648d37231e0384b9e7673d05a71c805
  +2d33995591700d28dab2a981d9aa1c1b
  +938e810ff307c91e9c71db1951d626e2
  +7197ab005cbf62eb87534e9565046c7e
  +76c74a72f5c4423cdfe712b1e094c705
  +6970e6209350fd4872f61232de6de4c4
  +ff1e26affac06a63377cb299b139f051
  +282c7b64cb49aa8d6d9b3902e858ee01
  +364ded1ae5536a7de60c388631c62a7a
  +33772fd38d48ab5e2af9da19ac0a57a2
  +c3cd53f270b6f2c90cedef280393316a
  +7fa3df3e898e84003370b7508fb1197f
  +d482c8e2dbada445bc42b5acc7c19fb7
  +2bb874c958b5920c5a30e64eb1f77977
  +1e24628bf4267a0d4d70e90bc9cb8301
  +c6ad085d3a908edfef296eff1d76d0f4
  +a87ff6b28555da307ae1457566c7d54d
  +2606de1537cc67239e7ea6e9c4f215ae
  +1e78c6c735f345c69520f0ff2e041f2c
  +07367b754860d1c176fd7b5cb7a530e0
  +528567c7710daf2ff6129e64a8ebdb08
  +a54f097f1361b635bde2320f39109fd9
  +0944ed06737d5c875f60c54c4b232daa
  +1878f76bfda90a8865095ea555b8dd45
  +501e41071b2d775d2f5937e7eb6de26a
  +0eb6cc9233a88feacb7ab28d21e87ae8
  +7a39b11879c2cc4579e2a2c4ea67d122
  +97f170e24df3a9fdd177843c3a02776c
  +201e15125105249507addd3090967894
  +c02dd79a529a7c6a1296309a47a2877a
  +adc96507fd2c76221222b33b73dd9292
  +46ffcbdae112435edb1e0b6f66859cbb
  +696b64eca6825fd628f10a1263077bff
  +813ef0bc04145562fb3d03a54b2f4b8e
  +15605a3407c1551375476401e39e5342
  +c8346e15ac6c745ca168f9223eff2439
  +72209f28cedf359957667eb913f5c57d
  +9d594e36709e5e9afca1eea8fbc26d50
  +7e63eb5c61256ae7728685b7af74d9bc
  +c683e12918f470c5778a69af6e9e55d6
  +768cc7983d4944f46aa3541c7353c4d8
  +a8c93832333f39e34b2e337e5e617953
  +ca8258d669b07b992f04ac1d2e58db02
  +c4a7d67e32d1a06621e19e721cfe972c
  +54bacec5eae8c4a2bc1093794bce5e2c
  +8a6d7f412dc7e53e3f0b025b7f073493
  +8a9c2d66d8bb5e267fe5ad1e3ff83efa
  +7be4b86f931da25073f5409b9885c376
  +efe082b4afffc6e5ef3fdbfabcbe817f
  +09c7aa151ecbb67865ecedbaf5c3f4ad
  +d3ea9bd2f33e17e699517912322fe972
  +b63d8a186e272754b70953ddd441e9fd
  +84a112f819bf780dd268c68f21238374
  +eab26f6455a08779bcb43bc48c02c717
  +OUT
  +
  +=bash
  +
  +test output created with:
  +
  +#!/bin/bash
  +str=$1
  +echo "$str"
  +for i in $(seq 1 200); do
  +    str=$(echo -n "$str$str" | md5sum | cut -d ' ' -f 1)
  +    echo "$str"
  +done
  +
  +=cut
  +
  +pir_output_is(<<'CODE', <<'OUT', "recursive md5sum (2)");
  +.sub _main
  +    load_bytecode "library/Digest/MD5.imc"
  +
  +    $S0 = "Hello World!"
  +    $I0 = 0
  +    
  +loop:
  +    print $S0
  +    print "\n"
  +    if $I0 >= 200 goto end
  +    $S0 = clone $S0
  +    $S0 = concat $S0, $S0
  +    $P0 = _md5sum($S0)
  +    $S0 = _md5_hex($P0)
  +    inc $I0
  +    branch loop
  +end:
  +    end
  +.end
  +CODE
  +Hello World!
  +ee41c968530f7715ab70805b341c3956
  +9548194ce84b2f7953386080da112c3a
  +9fb892cc0766429a1d8b0f752636c0fa
  +2fe752de4df1987b5682806c3ef37c5a
  +3030c16c1bac91e414f49394dbdd4f55
  +49d17233607383b6a7de5596cbfa40eb
  +1ef11b372f3d918c35901be67376207a
  +37369890630daa6fa20bab9293b3349e
  +1fe9a9f66fb556cccab339e684626a84
  +5039c55c89342feda99186afbe03c33d
  +52d20c3601d13cbb5caa9d26ab37723e
  +daaf532ebbbb00724a6a79be0cab1bfe
  +8c1e07121bd5e95013952fb5f55dd060
  +fc4bc5ee4d3347de8b517c27c0a8eed1
  +94d9d734e97421f64a71ec8d45781cdd
  +4b6ecae770f66dbb02ff3a59d6eedeb3
  +4ed31aa15d35ef52778508dc4cf7f84f
  +e14fc1e6320fa34660b27ef86b15caac
  +b79c5e129315c530b9b80a7c5a130c1b
  +9c4db0bc1cba0bc7a31e59db901d1362
  +75f5fcb94015872ca0c23bd5ed21c224
  +d3cdb5b27a0185365b42fdebfc5a1e33
  +98508cba7dfd5deeec4b8561c6bba42f
  +c0b8211ff3cd39cbbd6436e02cfedbda
  +783ed8f7d844efbc1c579b4b209360d9
  +a2b5528f3e2c506632601ea51df56d4f
  +2b46b6024f925419d79e6f86b33a3cf5
  +0276b6ca7eef6549d42b476ac4d2b049
  +e62ea2d5a6a7df48fe217909dc14a760
  +b84fe25ba8510f8a20da5e073992f6f9
  +0fb9bfff70bdd01b6e66f5864fb3c83f
  +3b10269c809a34d5239a0387422f66bc
  +3e0510deff0ef5e5b0dcbc0897d0622d
  +4d7fb6d3a50095b746f293ebe55a0bcd
  +cefd97e21fa803e960747a77e60fe39c
  +d7aa1e54cd8f7305391a236d1e56db42
  +3bbad66887cab24bb7e983bba3eac325
  +046b89e3a25c8372973113ff82b21abe
  +e4c174ab190ae7d59a2c9efa358ee60e
  +965544e7ee1040a234423c7708c45fd4
  +d92ed17d3817e51dac84e3bbd654f61c
  +34d00ed230a1fe8ba612f134326f0032
  +b8fe0ca50d70e605a0a65757affddf27
  +8cb68a7e99ac140f570188e92d1d2e45
  +6c45c11f3288af98126032b83454bdd7
  +82a5e65630a6df3d3272c4d706642804
  +17f51bff9ae985dee9547bbecef516a9
  +ace5283938a1003cbe1a25e32cb10057
  +364c61ec3fa510a2fdea988a04700ee2
  +de47aab46499b65cb73137c5ef161b28
  +877d37e40be25eff0e5a34f8701e9ff0
  +b2ba5696640f6c9d49ace67dbf178003
  +c38f63c86d919b38ceb8eb3bdae39f35
  +2ec338a2045b0d7a90ad279afd45eaee
  +05587d4ce4269f05c7e99e8bc790fed4
  +79e8bb5b94e687127b53f70eee64f403
  +1ff5dbd7c303f5ecb688cbc64e7a135f
  +07cfb35560313b13c83b34fa57076f14
  +5b562211545af5a95a873a5d8e3b9a6d
  +b08cf4400af1f8f13864da377fa97bff
  +bb706135638a8d77ea2c1ef5a5539bf7
  +6e08ae82fc5fbf55855602751b2d2c42
  +384b9112e19f5eaf187287e4dcee75e3
  +599ce20a11961b6e322106fed1b1f2e0
  +0e28143d15e6203ee316ed4c0558ff7a
  +4687a81afe698c362b3b3bb14d6c8ba9
  +419468fd66d946a0c892fa49106519ef
  +bb1b91d55152ba71777846fc2d4ebdf1
  +b405a24631d8fcd03eeed4249e9e1094
  +7be108fc15f3520b4ac637bd35597c95
  +8109f5a7ada16a51a9b6f1544ea85ea8
  +977433a6b14e766c41fa394007022096
  +124991f749a3f57bec7a72491349d2ab
  +8c671f8ebd350e9f79f127dd1c2dd048
  +f0ec2da36ad8cb2a0634fb2f70986c73
  +84a19613368ed9db0f3a42306872e29b
  +7b2f70096518e2d1d1a78e2c03065a69
  +9d150b414105e1289819df8efa567020
  +bb23274b2905ad3b623ccef55f75a468
  +4a75965a2b7f36e835201f3bfea10275
  +e22f29c343270f374c97687f3b7b0b66
  +2c55a15b3b9f3a97e114788ab26ce25e
  +a47134ba65aac9d0247b883e1ae387a2
  +367996de14121db2b8acc08b4716d125
  +ff7ff06cc7a6b12411d0f12dba779a13
  +f02344372ed7545d6dece5235c67327d
  +177a0082d277eb5efb6611a8fcaebf60
  +c9cef0b43563e9e12db3fe7b8a963a83
  +628867de0dcffae9f9435e0ea934769a
  +2a5389f9e88440e2e10b1ee61c476c9a
  +00ccb3071dc68daf6073d47453184ac7
  +70c89453989edb537bead30e83315166
  +2798118ce1c06a07989d89ab576a0b10
  +405ecd4ba790ebf79c7ee0eac3302430
  +ed76f9555303667976542e6481e6b6de
  +1aaac64d40d418414d5cc45e179998d2
  +725f3969179a13a88bd4710a68c7125a
  +cfdb37edcb3dfb65833e024b5190ac3d
  +bc33bcccad3bc958254cb5c9c24021e9
  +332b640f26b61dd553eeec4368e66ec2
  +d901771fd533f45aa9f8e6a89cdc50fd
  +a8b7c7a75da36a48cb521ba6c47b3d5d
  +0df89d833f2cfc704a54048a4fc25aa1
  +d0fdba931c657ae40db6de92fd1ad46f
  +3372e1f3859eb3133cbfb3ad4eb7ec87
  +58c050421e7063a3f228d8469a593706
  +e0efb8a7318d6aa3f4bb5504014169bd
  +bb76e71f387e28233023f6fcb363e77d
  +8708a28d0a12f36b8c814e1b23ae7d18
  +e4a2db9c1eb240a29519d47231a281b2
  +c1dccedeee5db48a8b850d4168f263b2
  +8b6540063c1867930ad609f78550ab45
  +61c8de37be3d7487e576a14ce519e402
  +4c39d3f4b7c5261b8b69278cd01cf61e
  +24b233c65768eafb144ffe4b237b2cda
  +624a97bd2d8d7945f0c79f660db79a6f
  +023eb3047f11a098e94c9b2f4dc395ad
  +77c08226ccc5722b777d79a2dacad01b
  +4ada0a4ed2a378da6ab3e36397ed933f
  +8e55ecd7bea4c69dd5411bed4f6af7a0
  +5890e55ed991429e062ed9bba2434fa2
  +6f29cdee26d8f59e399c75adc3ca963e
  +6f95058ad5897aac4c2c4e0a3447fddd
  +76a4b0b68df0015d5032f710a89b1989
  +553ea59edaec8245ca0b15f7f07d87c2
  +0ac57da5cd62c875b635d67c518d6972
  +a2216e7284bcf53f33da68b34170d869
  +08e4982dc84b56ad28948f0dd901bc05
  +d392a218b0f43a64489056256f969771
  +cd5543ca0553ee65d8b6d3404bf8b4ff
  +caeffa85a366f9bdd250cf1ecf3521ec
  +9a31f0f5b2f3e7e923bcc963502faf77
  +6ba7674cd36efbbbbcedab61d0cfdd95
  +df70da7d729efa4bcf037e0c2ed5aa0a
  +c69a07323e7105f3bbec3c287176c832
  +718f43dc297883de170d6e202dde9304
  +586ca71bfc8346b5d66613eb61a62392
  +220be4284d452c8205cf7767b774391c
  +54c9fc8f87b97a365834939ae4f047c6
  +baa53a78af5b174a674d0aecebcaf61c
  +897cdb62345099a3ce61c79148232d6b
  +b27b90a56eb999ed1b4f8f1fe20a03b8
  +bc37714ce2429460f363dfeb9e0fe130
  +451ce3e7aeb0fe575fd81acb9310c075
  +fc5223fd5a7457467413ef308484d3c7
  +18e58dd646ded1f8d973c0622c291ea8
  +1a34942df9b6b4c37d8694dd623cf4ed
  +1e540d9eb73f6a77135965f7ac52705f
  +01e6c944693e1ab23f176770948b63f3
  +440ad0e977d7b29240fc25645d271679
  +22c32fa8419ce0e9016e12f1cf9bd087
  +2fe03c2d4eab897c3ee7bc1ba687c1ca
  +9d7a2b063f7c375ea2528cd3c130a3c5
  +30318b3885c6f8e529d47e855a147753
  +09bbb9619dfd40414219a61fb5cb3f97
  +49f70a0b8dc368699e5509acc86067e8
  +1a3f2f5ac50b11d0f1441542f4103cdb
  +f62c4148d6a1a0d8bfc0830d92ed6ff8
  +c5868b2705f5a6c4e09b27e0c5e02fc4
  +d7611c94b236170077a9ccc3aed12b68
  +88fbb89660b33af29c0235c16e649d14
  +060054d8da83373e890586474bb0b844
  +ea0460399040570c24228aeba16ea548
  +e012db2951dacbc563fd1009908e26f7
  +9624f225fce79c7641f9fddedf1bb0e8
  +a13457b3b70f0377f93293ed26686b48
  +8c7f01c853c9f01248975e0c5838be36
  +f214e4e994f5d43e6d0b66d7c83909f7
  +31e1ef44d59205f8b70aa51247c4da5a
  +ee2f5bbb91dcb60545ed43b27ecf69b4
  +83f8f26970509c1f7958c42d3f4666c8
  +beb27e4616ed743cbde0e90e8fcedd85
  +64193d5ebb92c2a6e259818ee1a7b3cd
  +f36944249177ec4130719fd368eaf134
  +dfda44c7e068eb7d51f5925c4cbe4e3d
  +4f84611f754fbe80ba73cb278e6878e0
  +2bd7d30e73cb7a41842ca84782cfd3e6
  +c5532ffacc9cb4118b9dfcb6df5c92f1
  +d599e219cb43d15cd5a762052f71ab31
  +39a83debb4728212bc99b52375b2e6fe
  +773e28213d42e67a28d30509bb270741
  +36622bbee96e8d25d0a99f3d8e123b56
  +740495ae233ac2cc700183c550f871c3
  +0b34a880f5b434f40b5c777286dd9846
  +ae9773b3bc76125b06c0a6a441ec2ddc
  +39eaf3f8c28604aa5003f525ac900aac
  +c3c96034913b7b16451760c7cb707017
  +e696e2429c1c0ad48d68d5f8ccbf1d82
  +b45bc13eeb6ed7998fa94b676318fef1
  +16d61b48946c94a1b9a1cb7261ab812d
  +029bb7d6bf6b4c1eeb59c13543be7992
  +1840f1eb4b6516c1eb302d1b175070c5
  +a83c6cd9e67c60b5e745e40eb2d3b00f
  +6a7b7139dacfba962b392dfa5a9169a6
  +746d6f9a4c02bf3fcb1997a1d947a260
  +f67fa138069da8fce68c131106492372
  +614def545c4a4ecba07bf62966f0cc0b
  +982d93d2437c46edbf99f542900231c0
  +8408bf5f0144309374e66278bec290b2
  +982e0fde28cd2f62ef8db2d8dfd0f0d7
  +OUT
  
  
  

Reply via email to