From 3006a93e549418d56106029ff6a9844c99f3b71e Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Wed, 28 Jan 2004 17:31:06 +0000 Subject: [PATCH] Se agregan archivos complementarios para que ande el embperl. --- embperl/DumperISO.pm | 332 ++++++++++++++++++ embperl/Php2Embperl_Session.epl | 170 +++++++++ embperl/README | 14 + embperl/SimpleXMLISO.pm | 80 +++++ .../libapache-tempfile-perl_0.04-1_all.deb | Bin 0 -> 5714 bytes 5 files changed, 596 insertions(+) create mode 100644 embperl/DumperISO.pm create mode 100644 embperl/Php2Embperl_Session.epl create mode 100644 embperl/README create mode 100644 embperl/SimpleXMLISO.pm create mode 100644 embperl/libapache-tempfile-perl_0.04-1_all.deb diff --git a/embperl/DumperISO.pm b/embperl/DumperISO.pm new file mode 100644 index 0000000..4e92365 --- /dev/null +++ b/embperl/DumperISO.pm @@ -0,0 +1,332 @@ +# +# Copyright (c) 1998 Jonathan Eisenzopf +# XML::DumperISO is free software. You can redistribute it and/or +# modify it under the same terms as Perl itself. + +package XML::DumperISO; + +BEGIN { + use strict; + use vars qw($VAR1 $VERSION); + use Data::Dumper; + $VERSION = '0.4'; +} + +sub new { + my $class = shift; + my $self = {}; + return bless $self,$class; +} + +sub pl2xml { + my ($obj,$ref) = @_; + return $obj->pl2xml_string($ref); +} + +sub pl2xml_string { + my ($obj,$ref) = @_; + return( + "" . + &Tree2XML($ref, 1) . + "\n\n" + ); +} + +sub Tree2XML { + my ($ref, $indent) = @_; + my $string = ''; + + # SCALAR REFERENCE + if (defined(ref($ref)) && (ref($ref) eq 'SCALAR')) { + $string .= "\n" . " " x $indent . "" . &QuoteXMLChars($$ref) . ""; + } + + # HASH REFERENCE + elsif (defined(ref($ref)) && (ref($ref) eq 'HASH')) { + $string .= "\n" . " " x $indent . ""; + $indent++; + foreach my $key (keys(%$ref)) { + $string .= "\n" . " " x $indent . ""; + if (ref($ref->{$key})) { + $string .= &Tree2XML($ref->{$key}, $indent+1); + $string .= "\n" . " " x $indent . ""; + } else { + $string .= &QuoteXMLChars($ref->{$key}) . ""; + } + } + $indent--; + $string .= "\n" . " " x $indent . ""; + } + + # ARRAY REFERENCE + elsif (defined(ref($ref)) && (ref($ref) eq 'ARRAY')) { + $string .= "\n" . " " x $indent . ""; + $indent++; + for (my $i=0; $i < @$ref; $i++) { + $string .= "\n" . " " x $indent . ""; + if (ref($ref->[$i])) { + $string .= &Tree2XML($ref->[$i], $indent+1); + $string .= "\n" . " " x $indent . ""; + } else { + $string .= &QuoteXMLChars($ref->[$i]) . ""; + } + } + $indent--; + $string .= "\n" . " " x $indent . ""; + } + + ## SCALAR + else { + $string .= "\n" . " " x $indent . "" . &QuoteXMLChars($ref) . ""; + } + + return($string); +} + +sub QuoteXMLChars { + $_[0] =~ s/&/&/g; + $_[0] =~ s//>/g; + $_[0] =~ s/'/'/g; + $_[0] =~ s/"/"/g; + return($_[0]); +} + +sub xml2pl { + my ($obj,$tree) = @_; + + ## Skip enclosing "perldata" level + my $TopItem = $tree->[1]; + my $ref = &Undump($TopItem); + + return($ref); +} + +## Undump +## Takes a parse tree of the XML generated by pl2xml, and recursively +## undumps it to create a data structure in memory. The top-level +## object is a scalar, a reference to a scalar, a hash, or an array. +## Hashes and arrays may themselves contain scalars, or references to +## scalars, or references to hashes or arrays, with the exception that +## scalar values are never "undef" because there's currently no way to +## represent undef in the dumped data. + +sub Undump { + my ($Tree) = shift; + my $ref = undef; + my $FoundScalar; + my $i; + + for ($i = 1; $i < $#$Tree; $i+=2) { + if (lc($Tree->[$i]) eq 'scalar') { + ## Make a copy of the string + $ref = $Tree->[$i+1]->[2]; + last; + } + if (lc($Tree->[$i]) eq 'scalarref') { + ## Make a ref to a copy of the string + $ref = \ "$Tree->[$i+1]->[2]"; + last; + } elsif (lc($Tree->[$i]) eq 'hash') { + $ref = {}; + my $j; + for ($j = 1; $j < $#{$Tree->[$i+1]}; $j+=2) { + next unless $Tree->[$i+1]->[$j] eq 'item'; + my $ItemTree = $Tree->[$i+1]->[$j+1]; + next unless defined(my $key = $ItemTree->[0]->{key}); + $ref->{$key} = &Undump($ItemTree); + } + last; + } elsif (lc($Tree->[$i]) eq 'array') { + $ref = []; + my $j; + for ($j = 1; $j < $#{$Tree->[$i+1]}; $j+=2) { + next unless $Tree->[$i+1]->[$j] eq 'item'; + my $ItemTree = $Tree->[$i+1]->[$j+1]; + next unless defined(my $key = $ItemTree->[0]->{key}); + $ref->[$key] = &Undump($ItemTree); + } + last; + } elsif (lc($Tree->[$i]) eq '0') { + $FoundScalar = $Tree->[$i + 1] unless defined $FoundScalar; + } else { + ## Unrecognized tag. Just move on. + } + } + + ## If $ref is not set at this point, it means we've just + ## encountered a scalar value directly inside the item tag. + + $ref = $FoundScalar unless defined($ref); + + done: + return ($ref); +} + +### TestRoundTrip +### Tests the conversion of perl data structures into XML and back again +### +### Invoke with: +### +### perl -e 'use XML::DumperISO; &XML::DumperISO::TestRoundTrip();' +### +### The 5 sets of sample data below show some typical cases: + +sub TestRoundTrip +{ + my $TestRuns = + [ + + <<'END_TEST1', + + foo + +END_TEST1 + + <<'END_TEST2', + + Hi Mom + +END_TEST2 + + <<'END_TEST3', + + + value1 + value2 + + +END_TEST3 + + <<'END_TEST4', + + + foo + bar + + +END_TEST4 + + <<'END_TEST5', + + + Scalar + + ScalarRef + + + + foo + bar + + + + + value1 + value2 + + + + +END_TEST5 + + ]; + + my $TestNum; + my $TestData; + foreach $TestData (@$TestRuns) + { + $TestNum++; + + use XML::Parser; + my $Parser = XML::Parser->new(Style => 'Tree'); + my $Tree = $Parser->parse($TestData); + + my $DumperISO = new XML::DumperISO(); + my $Ref = $DumperISO->xml2pl($Tree); + + my $ReDump = $DumperISO->pl2xml_string($Ref); + + if ($TestData eq $ReDump) + { + print STDERR ("Test $TestNum: Success.\n\n" . + "Perl tree:\n" . + &Data::Dumper::Dumper($Ref) . + "\n\n"); + } + else + { + print STDERR ("TestRoundTrip: data doesn't match!\n\n" . + "Orig:\n$TestData\nRound Trip:\n$ReDump\n"); + } + } +} + + + +1; +__END__ + +=head1 NAME + +XML::DumperISO - Perl module for dumping Perl objects from/to XML + +=head1 SYNOPSIS + + # Convert Perl code to XML + use XML::DumperISO; + my $dump = new XML::DumperISO; + $data = [ + { + first => 'Jonathan', + last => 'Eisenzopf', + email => 'eisen@pobox.com' + }, + { + first => 'Larry', + last => 'Wall', + email => 'larry@wall.org' + } + ]; + $xml = $dump->pl2xml($perl); + + + # Convert XML to Perl code + use XML::DumperISO; + my $dump = new XML::DumperISO; + + # some XML + my $xml = < + foo + +XML + + # load Perl data structure from dumped XML + $data = $dump->xml2pl($Tree); + +=head1 DESCRIPTION + +XML::DumperISO dumps Perl data to a structured XML format. +XML::DumperISO can also read XML data that was previously dumped +by the module and convert it back to Perl. + +This is done via the following 2 methods: +XML::DumperISO::pl2xml +XML::DumperISO::xml2pl + +=head1 AUTHOR + +Jonathan Eisenzopf + +=head1 CREDITS + +Chris Thorman +L.M.Orchard +DeWitt Clinton + +=head1 SEE ALSO + +perl(1), XML::Parser(3). + +=cut diff --git a/embperl/Php2Embperl_Session.epl b/embperl/Php2Embperl_Session.epl new file mode 100644 index 0000000..560c63a --- /dev/null +++ b/embperl/Php2Embperl_Session.epl @@ -0,0 +1,170 @@ +[# +IMPORTANTE: ES NECESARIO QUE ESTE SCRIPT SE PONGA EN LA BARRA DE LA INTRANET NO +EN SISTEMAS/INTRANET PORQUE LA COOKIE FUNCIONA A PARTIR DEL DIRECTORIO EN EL +CUAL ESTE ESTE SCRIPT. +#] +[- +use CGI qw/:standard/; +use CGI::Cookie; + + +if (!defined($fdat{'redirect'})) { + $http_headers_out {Location} = 'http://bal747f.mecon.ar/sistemas/intranet'; + exit; +} + + +%cookies = fetch CGI::Cookie; +$archivo = '/tmp/sess_'.$cookies{'PHPSESSID747F'}{'value'}[0]; + +open (FILE, $archivo); +$linea = join ('',); + +$res = parseSession (linea => $linea); + +$udat{'user'} = $res->{'user'}; +$udat{'domain'} = $res->{'domain'}; +$udat{'nick'} = $res->{'nick'}; +$udat{'nro_doc'} = $res->{'nro_doc'}; + +$http_headers_out {Location} = 'http://bal747f.mecon.ar/'.$fdat{'redirect'}; + +exit; + +################# FIN SCRIPT + +sub parseSession +{ + my %params = @_; + my $op_value = $params{linea}; + my $pos = 0; + my $name; + my $type; + my $type2; + my $len; + my $result; + + + + while ($pos < 2){ + + #Obtengo el nombre del parametro + $name = substr($op_value, 0, index($op_value, '|')); + $op_value = substr($op_value, index($op_value, '|') + 1); #Depuro la linea + #Obtengo el tipo + $type = substr($op_value, 0, index($op_value, ':')); + $type2 = substr($op_value, 0, index($op_value, ';')); + + #Caso particular + if ($type2 eq 'N') { + $type = 'N'; + $op_value = substr($op_value, index($op_value, ';') + 1); #Depuro la linea + } + else { + $op_value = substr($op_value, index($op_value, ':') + 1); #Depuro la linea + } + + if ($type eq 's') { + #Obtengo la longitud + $len = substr($op_value, 0, index($op_value, ':')); + #Obtengo el resto de la linea + $op_value = substr($op_value, index($op_value, ':') + 1); + if ($name eq 'usuario') { + $result->{'user'} = substr($op_value, 1, $len); + ($result->{'nick'}, $result->{'domain'}) = split ('@', $result->{'user'}); + $op_value = substr($op_value, $len + 3); + $pos++; + } + elsif ($name eq 'documento') { + $result->{'nro_doc'} = substr($op_value, 1, $len); + $pos++; + } + else { + $op_value = substr($op_value, $len + 3); + } + } + elsif ($type eq 'i') { + $op_value = substr($op_value, index($op_value,';') + 1); + } + elsif ($type eq 'd') { + $op_value = substr($op_value, index($op_value,';') + 1); + } + elsif ($type eq 'b') { + $op_value = substr($op_value, index($op_value,';') + 1); + } + elsif ($type eq 'a') { + $op_value = parseContenido (cont => $op_value); + } + elsif ($type eq 'O') { + $len = substr($op_value, 0, index($op_value,':')); + $op_value = substr($op_value, index($op_value,':') + 1); + $op_value = substr($op_value, $len + 3); + $op_value = parseContenido (cont => $op_value); + } + + if (length($op_value) < 1) { + $pos = 3; + } + } + return $result; +} + +#Devuelve la linea sin el contenido +sub parseContenido { + my %params = @_; + my $op_value = $params{cont}; + my $type; + my $type2; + my $len; + my $seguir = 1; + + #Elimino todo hasta el { inclusive + $op_value = substr($op_value, index($op_value, ':') + 2); + + + while ($seguir) { + #Obtengo el tipo + $type = substr($op_value, 0, index($op_value, ':')); + $type2 = substr($op_value, 0, index($op_value, ';')); #Caso particular Null + + #Caso particular Null + if ($type2 eq 'N') { + $type = 'N'; + $op_value = substr($op_value, index($op_value, ';') + 1); #Depuro la linea + } + else { + $op_value = substr($op_value, index($op_value, ':') + 1); #Depuro la linea + } + if ($type eq 's') { + #Obtengo la longitud + $len = substr($op_value, 0, index($op_value, ':')); + #Obtengo el resto de la linea + $op_value = substr($op_value, index($op_value, ':') + 1); + $op_value = substr($op_value, $len + 3); + } + elsif ($type eq 'i') { + $op_value = substr($op_value, index($op_value,';') + 1); + } + elsif($type eq 'd') { + $op_value = substr($op_value, index($op_value,';') + 1); + } + elsif($type eq 'b') { + $op_value = substr($op_value, index($op_value,';') + 1); + } + elsif($type eq 'a') { + $op_value = parseContenido (cont => $op_value); + } + elsif($type eq 'O') { + $op_value = parseContenido (cont => $op_value); + } + + if (substr($op_value,0,1) eq '}') { + $op_value = substr($op_value,1); + $seguir = 0; + } + } + return $op_value; +} + +-] +1; diff --git a/embperl/README b/embperl/README new file mode 100644 index 0000000..709d56e --- /dev/null +++ b/embperl/README @@ -0,0 +1,14 @@ +$Id$ + +Archivos necesarios para que Intranet ande con embperl. + +Copiar los archivos a la ruta indicada: + +Archivo Ruta +------------------------------------------------------------------------ +SimpleXMLISO.pm /usr/share/perl5/Apache/Session/Serialize/ +DumperISO.pm /usr/share/perl5/XML/ +Php2Embperl_Session.epl /var/www/htdocs/ (DocumentRoot del apache) + +Instalar paquete libapache-tempfile-perl_0.04-1_all.deb. + diff --git a/embperl/SimpleXMLISO.pm b/embperl/SimpleXMLISO.pm new file mode 100644 index 0000000..4d67f81 --- /dev/null +++ b/embperl/SimpleXMLISO.pm @@ -0,0 +1,80 @@ +############################################################################# +# +# Apache::Session::Serialize::SimpleXML +# Serializes session objects using Storable and pack +# +############################################################################ + +package Apache::Session::Serialize::SimpleXMLISO; + +use vars qw($VERSION); +use XML::DumperISO; +use strict; + +$VERSION = '0.1'; + +################################################# +# Parsea un archivo XML con la limitacion de # +# que debe tener un tag por linea. # +################################################# +sub semiXMLParse { + my @xml = split( "\n", shift ); + my @isarray; + my $nivel = 0; + my $data; + my $eval = '$data='; + foreach my $line ( @xml ) { + $line =~ s/\s*(<.*>)\s*/$1/msg; + if ( lc( $line ) eq "" ) { + $eval .= "{"; + $isarray[++$nivel] = 0; + } + if ( lc( $line ) eq "" ) { + $eval .= "["; + $isarray[++$nivel] = 1; + } + if ( lc( $line ) eq "" ) { + $nivel--; + $eval .= "},"; + } + if ( lc( $line ) eq "" ) { + $nivel--; + $eval .= "],"; + } + if ( $line =~ /([^<>]*)(<\/item>)?/i ) { + $eval .= "'" . UnQuoteXMLChars( $1 ) . "'=>" + if ( not $isarray[$nivel] ); + $eval .= "'" . UnQuoteXMLChars( $2 ) . "'," + if ( $3 ); + } + } + chop $eval; + $eval .= ";"; + eval $eval; + + return $data; + + ###################################################################### + sub UnQuoteXMLChars { + my $str = shift; + $str =~ s/&/&/g; + $str =~ s/<//g; + $str =~ s/'/\\'/g; + $str =~ s/"/"/g; + return $str; + } +} + +sub serialize { + my $session = shift; + my $dump = new XML::DumperISO; + $session->{'serialized'} = $dump->pl2xml( $session->{'data'} ); +} + +sub unserialize { + my $session = shift; + $session->{'data'} = semiXMLParse( $session->{'serialized'} ); +} + + diff --git a/embperl/libapache-tempfile-perl_0.04-1_all.deb b/embperl/libapache-tempfile-perl_0.04-1_all.deb new file mode 100644 index 0000000000000000000000000000000000000000..88b725dc189630263d7bcb22a9da85463d3e8cf7 GIT binary patch literal 5714 zcmai#Wl+=&yT%cg?(UFSL0Wo68l^j=SvsUkBvwLTY3W))KtNg=1Qw(l>F(}s_@C#T zdCxoVhck1ox#OC9=KA=X`?)yO-O^41$I9Bm9_q|(Vebre_hn*Y5)Ex=5kxMxztmEqrF!&KsI;@saRWs-ze(d{E!ZLsYVZBYbY< zCqdo*`-q|;NlC^J*ZunZjI>?a{!3hR7~|?$;sHr(s4^7OsjgZ(^<;dT?{I?1s{P-hHU**VLpa;?}UCcSOgdr0F>}=20+W;u|kaYmDTLzmpZaL;aQ z@G@zlxPMwune~Sjno8g<{0*}6Gj0^ zY~IG3FD|-hjKx)w?AyQMh2zV$DQy3i$U>dk@Dkl;#MkQMOd*ztbZ6Sib@xo4zuj;| z`X~)RBl!7;Sd(5JO}>kHwoN`5ct%}||d)h@;ib0_E2;r2JN2&1X zmUY=&;GjYTII^lWiChx$ym37co>)1Bi#KhKuhG6HC}bABcuf-6L1BZ;PeW*TTmVso7T zAkYZ&J?U(HTtf=IkFLhApxB5pSrSxfW`(GT3nC)2&Un1%30qdEa#E$A6@H=Q<`iME z2P0nYMdHgx7BS_%N72;yWsxdE8d+X`bbstu(t5q=&)7G#;4$*%`e9g1z+(ixBJO?~ zF2zL39u~G!A1whKIcqCmSTVyDz)*iOoWDevG;6JBik(=b7}9iHWX#KJ_rITjywK^? z2*fti^1;{G?7vUUaG8X4AmEfznr}n{=vj9OT~mJ*-vh+8FUxdV z-OAociaz1vVV~UqUvC7MTJ6B8n5*&+0Qv(Q6il4{AoS1&Vwn($#*4wjCPRxPM&A?> z%%@tF3Z?^K2yn<^L}r>lsu&-28lEAxyjI%4={qUa6bgkb;UOw3tlJeX>>fsvka6PY z%UNt2QAFQSM#64(UMNSTg3?z1ey0#;V5fbF0ad_j4I;_w1>ai4b6_Ae3E$p#5seV?8U;6T&x0PUOqzn2h}9Fyl6 zI_Ah>e*-Hcm>S&*xOJTqW3k#;X!!pa4K7@V=CRSkD!a=7hnaSP{zqpF{E>EJ+7Hmb& z1&+gpEef|-T7ji+Cnbt=j^mh^g-uQ9mtSbA7TDFd@SBzf0Yz|{-b=LEct(AcUy`~S z!Z?RxNoBq5eRDnOZ|e!s3e_INPF1Da*t zDpO#-0`}&-+D+f>gf!eo;@M^72~myhyA?5-qw;6@`;Rg(GNSNZhNpdC-mzPiLi;>Y zh;mt}!e+()_2@J4AC>nw7N_GakO@C)gD~!(bSwvEjUCKa?cZuI`@AnbJ>9))y}HOA z(nuuIf4tza9=O5ll|UvM$g&56G6b9s?VB8IUQr0mS`!bFGckG7>saOpc%akq2GLA) ztYLS>e*oEJGX#{{m+N^N*<$QYm$;yN^k7rY^< zNl_yYCI1}o6(y&|0YYc-x4p)%f}xgqdSLGBv4)~=4LBQ% zBi7|`xT0CDEJyW}{@+ zsx-8}ANvdu|JdMgc(sA3sQF2Jcg<)=wTy3Q=U-&{=7!`jb~h+xkX)dy!iDFdmhZ3i zA~mrhC|gx$d`7NTH>*Ia(Z9@hQ!mB`gggF~mDZ{^vZ_1ErDN-D!@+|0b=?o&Ghgpe z{f{e#OXE7VC8eb5HjjJGyNxAv{C1{o8iu=Xa|VaYPo2U7x^<`P6u*aGXt89c<9<-C z$G(k3!+8I*%YfB%sRkNrHYeL&#W5dlrHhV%;3H@BtkXHFheNc)$lWZy(canw>#)%J z3^zAUD1OlVW{!#9-0IM&vM6@Q#ucSoNMf^u-HSIUS4BoxAb5PV<7xn7m_9yYA2H7I zvtZ%)zMOKMOT#?R56lQmmnSW}v_4Ow?@=NH>$pG+AHlgrcR{{>{b1x@=reRin)9iP z-^KMJ_YeJ;Ci=QPGf!u-Pby1O%LL~+BnPJzb`%9t^#t7u+xz6fdi z^7V-@N2fhxTgq8~@k!^vyc;AOQ;$cykFEl-*tVRUizzO)#OF_^pPW50I{9i%*Xu^9 zUK@cP6hiraqA4n5Z($stQh}x$d8H+%$C+OMw3f}xUafqYZix0E-FlmCpDug)p;h=# zkKW?PBc7P;dv3}S-58p_Q#cdHd(BtdbV4oeC6N9<{02TAPI?K!N4by!mp@U%L$mlt zN)yvr{JXgGhA$u#rjpvzcQ;Q$_>oHj=(JD^l9A)7vQVe1@B(E!p6K4d7;0)to9w)b z7~B|F0&RV7V*<~VcV7w!7}x6^QS~h?c@|%8n*7ZKSsYA09O4cnH)ofRancCsk5P|r z)jW;GyG3Ve^~8X#B3^iN`eYguxhlOwW>=_uYTdaNTrUY)zo=`VZ+K%j;&R+Vxd?hh ziIJ-A13T(xP0n={5G(#(FdIQ-ucpFK-$Cb(B*&>m^E|sIBh=}KxB^vHW5UYe2bEZg zV+jNHyhllq&2L8Wu5;twT$_;sNM3jP-ZSuGx3$&qi3$(yg_zvRvr5BLJ{RqnEqiI zoBI)Kmms>)kQuVbklSAi?aNp*q4<7^r|+a=mY+#idjS4zSO0N#x%*3K#DZu;g|*)`D$=2L+n;5oa%_SEZNs;w@HxrJBG#E;pr6_&&0Z zo$ah#+Q%eGLpKP9>Bb||h2v5#wm*V|Yv?7%AcD3~f2XJMdD71NFPZc7v6&1jp028@ zxAe%RKu2vzWc0FDnwMqwGriRDOMUdlJQEpzPiDe7uw+KJ_-Hrky9TWKB>U~!H#Er3 zpLC4lqg5kEOMTC_$8d^$w_@%o!MCRtDG+tVWk#T+|Fd>d6hAyV^mY2_My#WE2&K^x z)Wm_Es;|{v+|laCQ%DC*g@O;M<+gT>`SqHu#zXaXM{V1YiA)?KGk3Ik9h$1gR zC>^&vv1CtJP03H5R6o|VL2_oF%FC={x2i2a_11O~S8rlvY4X~GyyzSM6=iKy5$60U zl72R*w0v2Z6A?J!aR*;GO(N&;c8)VnFs+-7*)gmBlpL1aaaq=PKl}!grPVrhXOI?9 zq>H%pP1ymph%^Q^cDF2JsrtsO#~8lM(y@ zD-#o+os6DR>JLxVF0X$G?5}M7^?Fa^)-_w2!D!nox|dAl3$N#F)?X;MwO)8DOk1?$ zMpKE^PT1kDx^!2T(}uT^a(mXm{h*)R))+qiq><*$BH_r~`Z3B8do;VqBLA_Ci`h_{ zIR@hUoIlU5qqRyJ66J3~(tb00F0%W+r>GTI?;`zB3qv7WuWMQeabAdg`|2TfqbYf1 zO%-yu^XG?f|MzcBVtx9itb9riW1hLRj>3h=4-;8P-`Y#Jo+5U?tj5(O zrL4C$V53T#ZSggH)t2OG4EM|h>L7cGtK{Hx)$8LH`+lS(Z`kh(P}k|sUGL?1i@w^7 zCaKA4;PcmJmQU-!?c{2&TYl7MhLja+ zCCMH1-t7vMbPM`$N1jjVh^S`WPPc-V+AaNoodgZyWic|l|C+hiVR00Jp5D`kG ztc|8lsYhymLi!c;(O@q0yNAGtK9|iPjUEpl!DSllk(PMtU;{Vuap_!nWPa&Jvuy6X zreJ9at!I|Xy7f8ieUBE)H$wQ?Dfhx*mDO=&R3YXEv6L;Lj+rLr`vBEK)m+;^QO<|4 z%AQaywnJNq=@--GvtyIIGKxA_(eW-r{@2^Ey7$8dC5eg7*(AQmWu6^f{j5m{Je z2wjm$eojRw%M_)uC|zj=Ct1X=Mx*^0m%6$UXh!s z?=pZysN1_;0yWjpuj3p&0pZ09Xj~%V3(jTd184M&;o&>R1%Fg&N0QWxuU)s#GwCgu zUb^uM8rWVvdY!KwWEu@r1<1=d{*Q00nJr7AaOP~48Vo-=(j zbz$@87#$5eFU}@42IAx4_Rx}gEfmo{T@~&(jMt?In>VSk%(7|B|7q|+0M-@a#1_u{ zacE&Dr#MAyjL=Ao7W~3-L6=&<;+wSx&pihT!hq?QzNV4k*Or>EM|>O(@*P3cA!Qgs zA1bs3qq)+^bPrN;sPhrW(7mI&z__}_uTv|l^@1^lYI}y~RxR`E!#x!+PxQS zjUu3tbBSgb^5&0EpV*)$t=hyibUpoN@f-`7@Kj7%FQ=Y2t+~B27TLeN^=x#r?M2hS zWpo5WFWw{DJexhv$sl}pqr1-xh83N^#RU|W+F?g5oJawI+C$K;CrPgdBiUBtf)zqb=3bXYLv+N5sAzPn z$x@*PXFZt-C6Gq?CX>C-+7CZw2CXQ|7I!D_b)y)Z7u)kBXoRdRH9vH9Z@dQG9VJw! z?(3*6c{bL>-Sp(N@Cdv>EG6`|bPZIrct9tV+1Q$o5_Ml}??i0B7=CYK8NWYhl*FKG zn19xErto17z9xQ}KFakc=fs5ex1ozzzMap}OFC*NIR