Text-vFile-asData-0.08/0000755000175000017500000000000012101467725014750 5ustar richardcrichardcText-vFile-asData-0.08/META.json0000664000175000017500000000167612101467725016405 0ustar richardcrichardc{ "abstract" : "parse vFile formatted files into data structures", "author" : [ "Richard Clamp " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 6.6302, CPAN::Meta::Converter version 2.120630", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Text-vFile-asData", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Class::Accessor::Chained" : "0", "Test::More" : "0.88" } } }, "release_status" : "stable", "version" : "0.08" } Text-vFile-asData-0.08/MANIFEST.SKIP0000644000175000017500000000036212101467715016646 0ustar richardcrichardcCVS/.* \.svn/.* ^.git \.cvsignore$ \.Inline/.* _Inline/.* \.bak$ \.tar$ \.tgz$ \.tar\.gz$ ~$ ^mess/ ^tmp/ ^testdata/ ^blib/ ^Makefile$ ^Makefile\.[a-z]+$ ^Build$ ^pm_to_blib$ ^_build/.* ~$ ^MYMETA\. ^Text-vFile-asData- bin/SystemsSupportRota Text-vFile-asData-0.08/Changes0000644000175000017500000000345512101467715016251 0ustar richardcrichardc0.08 Monday 28th January, 2013 Merge fix from Ashley Willis - Only " should get special treatment as a quote character. https://github.com/richardc/perl-text-vfile-asdata/pull/1 0.07 Wednesday 25th August, 2010 Switch to ExtUtils::MakeMaker as Module::Build got uppity and started generating bad Makefile.PL files 0.06 Friday 20th August, 2010 Fix case with ' in entities (Richard Russo) 0.05 Saturday 25th June, 2005 Removed a leftover C from t/parse_line.t (spotted by Leo) 0.04 Tuesday 31st May, 2005 Removed the paragraph about rt.cpan.org from the docs as it's just not fitting the way I want to deal with stuff. Make the parsing of blocks case-insenitive as the RFCs call for (they just happen to always use upper-case identifiers) Closes #12381 (JC with some modifications) Also uncovered a bunch of other block-related bugs. Will now die if a BEGIN occurs without a matching END generate_lines now wraps Tightened the logic for unfolding. The RFC states the folding sequence is exactly \r\n[ \t], where before we were looking for \r\n\s. Since \s can match unicode whitespace this was wrong. 0.03 Thursday 26th May, 2005 Moved CRLF removing logic down a bit lower into _unwrap_lines. Elminate Text::ParseWords by writing our own more C-like version, fixes the vCard image segfault issue. 0.02 Wednesday 6th October, 2004 Moved non-vFile files from examples/ to bin/ as it was mightily confusing the round-trip test. Added bin/holidays_ical Added bin/wgo Fixed module name in bin/v2yaml Deleted the Encode cargo. Checking for a BOM on each and every line is batshit. Added ->preserve_params option to create a new structure which preserves the order of the params. 0.01 Thursday 19th February, 2003 Initial CPAN release Text-vFile-asData-0.08/t/0000755000175000017500000000000012101467724015212 5ustar richardcrichardcText-vFile-asData-0.08/t/03usage.t0000644000175000017500000000242512101464332016641 0ustar richardcrichardc#!/usr/bin/perl use strict; use warnings; use Test::More; # Show an example of API in use, and test it at the same time use Text::vFile::asData; my $data = Text::vFile::asData->new->parse(\*DATA); is(ref $data, 'HASH', 'Got back a hash ref'); # Should have one VCALENDAR object is(scalar @{ $data->{objects} }, 1, 'Found one object'); is($data->{objects}->[0]->{type}, 'VCALENDAR', ' and it\'s a VCALENDAR'); # Get all the properties of this object. There should be two (the other # properties in there, DTSTART, etc, belong to the VEVENT object my @properties = keys %{ $data->{objects}->[0]->{properties} }; is(scalar @properties, 2, 'Got 2 properties, as expected'); is($data->{objects}->[0]->{properties}->{'VERSION'}->[0]->{value}, '2.0', 'VERSION is 2.0'); is($data->{objects}->[0]->{properties}->{'PRODID'}->[0]->{value}, '-//hacksw/handcal//NONSGML v1.0//EN', 'PRODID looks right'); # Get the event info my $e = $data->{objects}->[0]->{objects}->[0]; is($e->{type}, 'VEVENT', 'First sub object is a VEVENT'); done_testing(); # Local Variables: # cperl-indent-level: 4 # End: __DATA__ BEGIN:VCALENDAR VERSION:2.0 PRODID:-//hacksw/handcal//NONSGML v1.0//EN BEGIN:VEVENT DTSTART:19970714T170000Z DTEND:19970715T035959Z SUMMARY:Bastille Day Party END:VEVENT END:VCALENDAR Text-vFile-asData-0.08/t/pod.t0000644000175000017500000000020212101464332016143 0ustar richardcrichardcuse Test::More; eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok(); Text-vFile-asData-0.08/t/parse_line.t0000644000175000017500000000106612101464332017513 0ustar richardcrichardc#!/usr/bin/perl -w use strict; use Test::More; use Text::ParseWords (); use Text::vFile::asData (); if (eval "require Test::Differences") { no warnings 'redefine'; *is_deeply = \&Test::Differences::eq_or_diff; } sub same { is_deeply( [[ Text::vFile::asData::parse_line( @_ ) ]], [[ Text::ParseWords::parse_line( @_ ) ]], "same( " .( join ", ", map { "'$_'" } @_ ) ." )"); } for my $string ( 'foo', 'foo:', 'foo:bar', 'foo:bar:' ) { for my $keep (0, 1) { same( ':', $keep, $string ); } } done_testing(); Text-vFile-asData-0.08/t/02examples.t0000644000175000017500000000242212101464332017347 0ustar richardcrichardc#!/usr/bin/perl use strict; use warnings; use Test::More; use File::Find; use IO::File; # Make sure the examples in the examples/ hierarchy all parse and roundtrip my @samples = (); find(\&wanted, 'examples'); sub wanted { push @samples, $File::Find::name if -f $_ and $_ ne 'README'; $File::Find::prune = 1 if -d $_ and $_ eq '.svn'; } my $class = 'Text::vFile::asData'; if (eval "require Test::Differences; 1") { no warnings 'redefine'; *is_deeply = \&Test::Differences::eq_or_diff; } require_ok( $class ); for my $preserve (0, 1) { diag "preservation is " . ($preserve ? "on" : "off"); foreach my $file (@samples) { my $parsed = $class->new->preserve_params( $preserve ) ->parse( IO::File->new($file) ); ok( $parsed, "parsed $file" ); my @generated = $class->new->generate_lines( $parsed ); ok( scalar @generated, "generated vCal" ); is_deeply( $parsed, $class->new->preserve_params( $preserve ) ->parse_lines( @generated ), "and it round tripped") or do { print "# generated:\n", map { "# $_\n" } @generated; my $fh = IO::File->new( $file ); print "# from:\n", map { "# $_" } <$fh>; }; } } done_testing(); Text-vFile-asData-0.08/t/01vfile.t0000644000175000017500000001760712101464332016650 0ustar richardcrichardc#!/usr/bin/perl use strict; use warnings; use Test::More; if (eval "require Test::Differences") { no warnings 'redefine'; *is_deeply = \&Test::Differences::eq_or_diff; } my $class = 'Text::vFile::asData'; require_ok( $class ); isa_ok( my $p = $class->new, $class ); # rfc2445 4.1 is_deeply( [ $p->_unwrap_lines( "FOO:This is a te", " st. Not a", " real foo." ) ], [ "FOO:This is a test. Not a real foo." ], "line unwrapping", ); is_deeply( $p->parse_lines( "FOO:This is a te", " st. Not a", " real foo." ), { properties => { FOO => [ { value => "This is a test. Not a real foo." } ], }, }, "simple property" ); is_deeply( $p->parse_lines( 'CHECK:one\, two' ), { properties => { CHECK => [ { value => 'one\, two' } ], }, }, "value containing an escaped comma" ); is_deeply( $p->parse_lines( "CHECK:one,two" ), { properties => { CHECK => [ { value => "one,two" } ], }, }, "value containing an unescaped comma" ); is_deeply( $p->parse_lines( "CHECK;testing=one:two" ), { properties => { CHECK => [ { value => 'two', param => { testing => 'one' } } ], }, }, "a single parameter" ); is_deeply( $p->parse_lines( "CHECK;testing1=one;testing2=two:ffff" ), { properties => { CHECK => [ { value => 'ffff', param => { testing1 => 'one', testing2 => 'two', } } ], }, }, "multiple parameters" ); is_deeply( $p->parse_lines( "BEGIN:PIE", "FILLING:MEAT", "END:PIE", ), { objects => [ { type => "PIE", properties => { FILLING => [ { value => 'MEAT' } ], }, }, ], }, "nest 1" ); is_deeply( $p->parse_lines( "BEGIN:PIE", "FILLING:MEAT", "BEGIN:CRUST", "BASE:CORN", "END:CRUST", "END:PIE", ), { objects => [ { type => "PIE", properties => { FILLING => [ { value => 'MEAT' } ], }, objects => [ { type => "CRUST", properties => { BASE => [ { value => "CORN" } ], } }, ], }, ], }, "nest two" ); eval { $p->parse_lines( "BEGIN:PIE", "FILLING:MEAT", "END:FUN", ); }; like( $@, qr/^END FUN in PIE/, "nest failure" ); eval { $p->parse_lines( "BEGIN:PIE", "FILLING:MEAT", ); }; like( $@, qr/^BEGIN PIE without matching END/, "still nested nest failure" ); # rt #12381 eval { $p->parse_lines( "BEGIN:PIE", "FILLING:MEAT", "end:Pie", ); }; is( $@, "", "case-insensitive nesting" ); is_deeply( $p->parse_lines( "FOO;BAR=BAZ;QUUX=FLANGE:FROOBLE" ), { properties => { FOO => [ { param => { BAR => 'BAZ', QUUX => 'FLANGE', }, value => 'FROOBLE', }, ], }, }, "simple params" ); is_deeply( $p->parse_lines( 'FOO;BAR="BAZ was here";QUUX="FLANGE":FROOBLE' ), { properties => { FOO => [ { param => { BAR => 'BAZ was here', QUUX => 'FLANGE', }, value => 'FROOBLE', }, ], }, }, "quoted params" ); is_deeply( $p->parse_lines( 'FOO;BAR="BAZ was here";QUUX="FLANGE wants the colon: ":FROOBLE' ), { properties => { FOO => [ { param => { BAR => 'BAZ was here', QUUX => 'FLANGE wants the colon: ', }, value => 'FROOBLE', }, ], }, }, "quoted params" ); is_deeply( $p->parse_lines( 'FOO;BAR="BAZ was here";QUUX="FLANGE wants the colon: ":FROOBLE: NINJA' ), { properties => { FOO => [ { param => { BAR => 'BAZ was here', QUUX => 'FLANGE wants the colon: ', }, value => 'FROOBLE: NINJA', }, ], }, }, "quoted params colon in the value" ); # Richard Russo points out this one is_deeply( $p->parse_lines( q{ORGANIZER;CN="Will O'the Wisp":William} ), { properties => { ORGANIZER => [ { param => { CN => "Will O'the Wisp", }, value => 'William', }, ], }, }, "quoted param with embedded quote marks" ); # Leo's corner case; you will sometimes have two params with the same # names (pesky vCards) is_deeply( $p->parse_lines( 'FOO;corner=fruit;corner=case:BAZ' ), { properties => { FOO => [ { param => { corner => 'case', }, value => 'BAZ', }, ], }, }, "collapsing params" ); $p->preserve_params( 1 ); is_deeply( $p->parse_lines( 'FOO;corner=fruit;corner=case:BAZ' ), { properties => { FOO => [ { param => { corner => 'case', }, params => [ { corner => 'fruit' }, { corner => 'case' }, ], value => 'BAZ', }, ], }, }, "collapsing and non-collapsing params" ); # Another one via Leo, parsing vCards with embedded images leads to segfaulty # death - probably just because we try and tokenize 49k of data with a simple # regex open my $fh, "t/user_with_image.vcf" or die "couldn't open test card"; my $data = $p->parse( $fh ); ok( 1, "didn't segfault on parsing an embedded image" ); ok( exists $data->{objects}[0]{properties}{PHOTO}[0]{param}{BASE64}, "Looks like we handled the vcard too" ); done_testing(); Text-vFile-asData-0.08/t/user_with_image.vcf0000644000175000017500000014100412101464332021055 0ustar richardcrichardcBEGIN:VCARD VERSION:3.0 N:User;Test;;; FN:Test User ORG:I've got a picture me; PHOTO;BASE64: TU0AKgAAfsj///////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////+9wcC9wcC9wcC9wcC/wcC/wcC/wcC/wcC/wcC/wcC/wcC/wcC9wcC9wcC9 wcC9wcDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDGxsa3 t7e+vr7MzMy1tbXGxsa8vLzExMTAwMDExMS/v7++vr7GxsbExMS+vr7AwMC7u7vCwsLAwMDAwMDH x8fExMS+vr7BwcHExMS4uLjIyMjBwcHDw8O6urrKysq3t7e/v7++vr66urrFxcW+vr64uLjGxsa/ v7/AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD///////+9wcC9wcC9wcC9wcC/wcC/ wcC/wcC/wcC/wcC/wcC/wcC/wcC/wcC9wcC9wcC/wcDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDCwsLIyMi/v7/AwMC8vLzExMTBwcG/v7/BwcHCwsK+vr6/ v7/FxcXCwsK+vr7Dw8PAwMDDw8O+vr68vLzAwMC7u7u3t7fAwMDIyMi6urrExMTBwcG/v7+urq6z s7PJycnBwcHCwsK9vb3FxcXAwMC6urrFxcW+vr7AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMD///////+/wcC/wcC/wcC/wcDAwMDAwMDAwMDAwMDAwMDAwMDAwMC/wcC/wcC/wcC/wcC/ wcDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMC+vr7Hx8fE xMS4uLjBwcHCwsLHx8e6urrDw8O+vr69vb3BwcHDw8O/v7+/v7/FxcXBwcHCwsK+vr7AwMDExMS8 vLy5ubnFxcXDw8O6urq+vr7BwcG5ubmcnJx/f3+3t7fAwMDGxsa/v7/ExMTCwsK8vLzFxcW9vb3A wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD////////AwMC/wcDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMC/wcDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMC7u7ufn5/Gxsa+vr7AwMDDw8PHx8e6urrExMS7u7u9vb3Dw8PB wcG9vb3AwMDCwsK9vb2/v7+9vb3CwsLKysrCwsK9vb3Gxsa8vLzAwMC+vr7ExMS+vr6dnZ1VVVWA gIC1tbXGxsa/v7/AwMDDw8O/v7/ExMS9vb3AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMD////////Bv8DAwMDBv8DAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDBv8DAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMC7u7tmZma5ubnL y8u7u7vExMTDw8O+vr7ExMS5ubm+vr7ExMS+vr6+vr7AwMC2trbBwcHCwsK9vb29vb3ExMTBwcG7 u7vAwMC8vLzIyMjBwcHFxcXIyMi1tbVfX19XV1ejo6PCwsK+vr69vb3Dw8PAwMDDw8O/v7/AwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD////////Dv8DBv8DBv8DBv8DBv8DAwMDAwMDA wMDAwMDAwMDAwMDAwMDBv8DBv8DBv8DBv8DAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMC8vLxLS0uVlZXIyMi6urrDw8O/v7/CwsLDw8O6urrBwcHExMS7u7vC wsK/v7+jo6O+vr7KysrGxsa7u7u9vb2/v7+9vb3AwMC6urrGxsa8vLy8vLzGxsbHx8eNjY1MTEyR kZG+vr6/v7+8vLzExMS/v7/BwcHBwcHAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD/ ///////EvsDDv8DDv8DBv8DBv8DBv8DAwMDAwMDAwMDAwMDBv8DBv8DDv8DDv8DDv8DDv8DBv8DA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMC+vr5dXV1jY2OysrLA wMDAwMC+vr7Dw8PBwcG7u7vExMTDw8O5ubnGxsa+vr6QkJCSkpK5ubnKysrAwMC9vb3BwcHBwcHC wsK7u7vBwcG6urq7u7u+vr7Dw8O0tLRJSUmEhIS+vr7Dw8O9vb3ExMS+vr6/v7/CwsLAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD////////EvsDEvsDDv8DDv8DBv8DAwMDAwMC/wcDA wMDAwMDAwMDBv8DDv8DDv8DEvsDDv8DBv8DAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMB6eno+Pj6dnZ3Hx8e8vLy/v7/BwcHAwMC8vLzGxsbCwsK4uLjJycm9 vb2Dg4NWVlaYmJjDw8PBwcG+vr7CwsLAwMC9vb3BwcHDw8PCwsLGxsa9vb25ubnIyMhGRkZ+fn6/ v7/Hx8e/v7/FxcW9vb29vb3CwsLAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD///// ///CvL7HwcPHw8S/vb6+vr7CxMPCxMO8wL+9v77DxcTCxMO8vLy+vL3IxMXJw8XCvr/Bv8DAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCHh4dLS0tlZWW/v7/B wcHAwMDCwsK/v7/FxcXDw8O9vb3AwMDDw8Ozs7OcnJxMTExqamq/v7/CwsLExMTExMS+vr6/v7/B wcHCwsK6urrHx8e5ubnBwcG6urpISEh9fX2/v7/BwcG6urrLy8vCwsK7u7vCwsLAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMC+vr7AwMDCwsLBwcG+vr69vb29vb2+vr7ExMS7u7vJycm+vr7Dw8O2trbF xcXAwMC/v7/Ly8u8vLy/v7/Dw8O8vLz////////Fv8HDv8DBvb69u7y8vr29wcC+wsG7wb+/xcO9 wcC7v77Bw8LIxsfLx8jEwMG9ubrBv8DAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMCHh4dLS0tlZWW/v7/BwcHAwMDCwsLAwMDCwsLBwcG+vr7CwsLGxsa+vr6x sbFKSkpdXV21tbXBwcHAwMDCwsLBwcHAwMC/v7/Jycm8vLzDw8O+vr7Gxsa3t7dMTEx+fn7BwcHE xMS5ubnHx8fCwsK+vr7CwsLAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDBwcHBwcHBwcHAwMDA wMDAwMDAwMDCwsK5ubm/v7+6urrLy8vCwsLFxcW6urrBwcHDw8O+vr7BwcHExMTDw8P////////C vr+/u7y9u7zAwMDAxMO/xcO8xcK9xsO8xcK5wr+6wL67v766urq5t7jDv8DOysvBv8DAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCHh4dLS0tlZWW/v7/BwcHA wMDCwsLCwsLAwMC+vr6+vr7BwcHDw8PExMTDw8NRUVFTU1Ovr6/Dw8O8vLy+vr7ExMS/v7+8vLzM zMy7u7u/v7/ExMTDw8OlpaVLS0t+fn7BwcHGxsa5ubnCwsLCwsLCwsLCwsLAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMC/v7+/v7+/v7/BwcHBwcHBwcG/v7/CwsLBwcG/v7+5ubnMzMzFxcXDw8PA wMDFxcW5ubnAwMC/v7+9vb3ExMT////////Dv8C+vL3AwMDExsXAxsS4wb61wLy4xMCsuLS1wLy+ x8TEysjExsW/v7+8uru5t7jAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMCHh4dLS0tlZWW/v7/BwcHAwMDCwsLExMS/v7++vr6/v7++vr68vLy/v7/FxcVd XV1SUlKvr6/IyMi6urq8vLzGxsa9vb28vLzIyMi5ubnCwsLIyMitra2AgIBERER8fHy9vb3FxcW6 urrAwMDCwsLExMS/v7/AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMC+vr68vLy9vb2/v7/BwcHA wMC+vr6/v7/IyMjExMS6urrBwcG+vr6/v7/Hx8fFxcW3t7fFxcXAwMC1tbW8vLz////////Fw8TD wcLBwcG9wcC3wL2yvbmxwLu2xcDD0s3Az8q6xcGzvLm8wL/JycnGxMW5t7jAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCHh4dLS0tlZWW/v7/BwcHAwMDC wsLBwcG/v7+/v7/BwcG+vr66urq7u7vBwcFfX19TU1Ovr6/IyMi6urq8vLzGxsa9vb3AwMDCwsK7 u7vIyMjCwsKMjIxaWlpCQkKBgYG4uLjCwsK+vr7BwcHBwcHFxcW9vb3AwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDBwcHAwMC+vr6+vr6/v7/AwMDAwMDAwMC6urrDw8PBwcG/v7+9vb3CwsK/v7/BwcHB wcG9vb3Hx8fHx8e/v7+7u7v////////CwMHBwcG9v764vry5wr+9ycW7zMa1yMKnuLKyw726xsK1 wLyytrW5u7rFxcXOzM3AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMCHh4dLS0tlZWW/v7/BwcHAwMDCwsK8vLy/v7/CwsLCwsLBwcHAwMDAwMDAwMBWVlZW VlawsLDDw8O7u7u+vr7FxcXAwMDDw8PAwMDBwcHExMSoqKhqampFRUVLS0uTk5O4uLi/v7/BwcHC wsK+vr7ExMS9vb3AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDDw8PDw8PDw8PBwcG+vr6+vr7BwcHD w8O/v7++vr6/v7/IyMi+vr7Ozs7Jycm6urq9vb3BwcGurq69vb3Ozs7BwcH///////+8vLzAwMC8 wL+4wb6/ysa+zcijtrCCl5A+UUtbbmiTop3BzcnK0M63u7q0tLS/v7/AwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCHh4dLS0tlZWW/v7/BwcHAwMDCwsK7 u7vCwsLDw8O/v7/AwMDFxcXDw8O7u7tRUVFiYmK3t7fAwMC+vr7BwcHCwsLCwsK/v7+/v7/ExMSv r699fX1NTU1DQ0NYWFitra2+vr69vb3Dw8PCwsK6urrDw8PAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDDw8PExMTAwMC6urq4uLi9vb3CwsLDw8O9vb3CwsLGxsafn5+5ubnJycm9vb2/v7+6 urpycnKNjY3IyMjBwcH///////++wL/CxsW+x8S6xsK4y8WmvbNphHkrRjsZNCkNJxwxSD6El5G+ ysa+x8S4vrzExsXAwMDBv8DDv8DBv8C9wcC8wsC/wcC/wcC/wcC9wcC8wsC9wcDBv8DDv8DBv8DA wMC/wcCGiIVKTEtkZmO+wL/Awr+/wcDBw8C8vr3ExsPDxcS6vLm7vbzDxcLBwcG1tbVUVFRwcHDC wMPBwcHDwcTDw8PAvsHBwcG6uLu9vb3Fw8aamppbWVw9PT1IRkliYmLAwsHCxsW6vr3BxcS+wsG0 uLe/w8K+xMK9wcC9wcC9wcC9wcC9wcC9wcC9wcC/wcC8vLrAwL7CwsC8vruztbKusq+0uLW7wb27 wb23vbnAxsK0urZrcW2Jj4u2vLi9w7+/xcOssK83OzpWWlm0trW5u7r///////+5wsG1wL6tvri0 y8O41spUeWgYQi8GMR4OOSYLNSIUNiZGZFijurKyw72/y8mxt7XHxcbAt7jOv8K/tre+ycPB0sqp sq2+xMC1vrmwu7V3iIC8yMLHwcHHvL7Dv767u7m9w7+Bi4M9RkFmcGi3wLvAysK3vbm9xL3BxcK6 v7m4vLnCx8HCxsOtsqzHycaQko9WVFezsbTBvMLHxci/usDBv8LDvsTFw8a/usDMys2XkphWVFdQ S1FIRklVUFaIiIrIzsy3wrytuLK1wbu7x8G2xb60w7y3yMDE08yltK2+zca2xb6xvbe8yMLBzMa2 v7rGycOur6rJzMa/xL6apJwzPzZBUUeitKm6zsOzx7y0yr56kIQdMSYyRjuxw7i1x7y1xr62xcAd KSU5RECttrO2v7z///////+8wMG7xMO2x8Gvyb6ApJYoU0AKOiQIOSMAKRMQOyc4XUw5WElIX1dp fHaYqaW9yMS+vr7Gvb7LvL/Bu7uGl493kYa1xr7L19HF0cuYqaE9V0yAk4u5tbTGurzJxcTFx8S4 v7iFj4dIUkpZY1uvubG+yMDByMG4v7i6v7nAxb+6v7m2u7XFyMLHysSxtK5naWaSkJPDvsS/usDF wMbGwcfEv8XEv8W/usDJxMqkn6VXUlhCPUNcV11KRUtiXWPExMaxure9ycN6hoBQX1iZqqK1yMC9 0smpvrWKn5ZgdWyVqqFYa2N6jYWis6u1xr69ycO7wrttcmuttKy1v7adqqAgMiYbMSRacmSlwLGr x7iYtKU1UUIdOSobNieduKmyyr2swbilurMYKSNPXlmwvLi4w7/////////Fv8PAwMK9yMSvxrxR cmUKNSIHNB8KNyIeRTJIaViEn5G2yr+vwLpNXFcWJSKVoZ28xcLGyMXBu7vQ0M5heG4mRjmYr6Wi ta2ou7NrgngIKBtVbGK/v73KxMTExsO5vbq4vLmIiodMTktaXFmtr6zAwr/GyMW7vbq6vLnExsO9 v7y3ubbFxcPJyceLi4llZWO+vL/EwsW+vL+9u77Fw8a9u77Fw8a6uLuhn6JUUlVMSk1UUlU5Nzpk YmW0srXAwMK1vru0wLqdqaMtPDVBUkq1yMCwxbytwrk2TUNHXlSEm5EOIxoqPzZAU0uaraWzxLyv u7I4RDuir6awwLagtKkfNyohPC4aNiiVtKWtzL1mhXYSMSI0U0QbNymLp5mzzsCrwriar6gbLCZ4 h4K2wr68x8P////////Pvsa/tru6wL6zyL9BYlUKNSINOCQFLxsjRDOrw7XJ1s20vra9yMSuurZI V1QuPzmaqaS0v7mvsa6/yMNLa14JLyCPraGzzcLG3dOGoZYUOCpDYVW3u7jAvr3AxsK5wr3AwL6H hYQ/PT5bWVibmZq9u7rDwcLCwL/CwMG/v73Avr/GxMPCwMGnpaRlY2SZl5jBv8K9vb/Ixsm7u73E wsW6urzHxcizs7VZV1pPT1FKSEtISEpjYWSfn6HFw8a5u7rEysiyvbfEz8l1gXsOHxeOoZm0ycCN opkwRz2KoZeasacaMScZMCYPJBuswbi0x7+braIoOi+jt6yqwLSTq54jPjBZeGkQLyB0lYWUtaUr TDw1VkZXdmcaOSpzj4GpxLa0ycKYq6UlNjCfrqm6xcG8x8P////////XvMfEs7u+vr61yMA+YlQJ NCEQOycRNiSIoJKturCusavJysWztbS6w8CUpaEeMyxbcmqyx77G0cuyw7tSeGkeSjl1mYuWtqmD oZVoiXwXQDBNbmG3wLu9v7y9yMK3wrzDwcKalJY/OT1OSEpuam21sbLEwMPGwsPHw8a9u7zEwMPN ycrAvL+MiIlQTE+6uLu/v8G9v8DNzc+6vL3Fxce/wcK0tLaMjo9QUFJHSUpGRkhpa2yhoaO8vr+/ v8HAwsG+xMLAycSmsau2wrxKWVJKW1O3ysJGW1Jsg3m30caatKklPzQkPjM0S0G91Mqxxr2PpZkm PDCdtaiow7V4lIYVNCWPrp86W0tNbl5lhnYtTD2FpJWRrZ8UMCJuiXuuybu2y8SXqqQtPjiywby4 w7+6w8D////////ZuMXQucPHxcaww7tFaVsAKhYMOSQoTTuovLDO1c3Ewb3V0M26urq9xsOswbwV MCcXNSuNp5yTpJxUaWATPS0ALx0iSDkcPC8kRDckRTgAKBhfgHO/ysTBxcK7x8G0v7m/vcC4r7Rm XWJIQkZGQESalJjCvMDDv8LEwMPCvsHGwsXDwcS/vcCEgoVMSk2tq67ExMa/wcLDxcaztbbDxca/ wcKLjY5WWFlSVFVTVVaEhoe0tre1t7i5u7zGyMm/wcC5vbrCyMSzvLe4w72fq6UyQztqfXU5TkWe tauxy8Cdt6weOC0SLCFKZFmivLGtxLqasqUsRDeatae30sRtiXseOiysy7x+nY4rSjstSTtdeWuw y72yzb8PJxpheWywxbyww72aq6U4R0K2wr61vru3wL3////////Xs8HVvsjIxseqvbVbhHQALRgH NyE5XkyitKjMz8jAuLa5sa/AwMC8x8OjvbY2V0wkRDmPqp+DlIxEW1ENNycMPCpTeWpdfXBujIBF ZVgBKhpri361wLq+wL28x8HBzMa+vL/GwMSjnaFtZ2tQSk5qZmmuqq3DwcTBv8K/vcDDwcS8vL7D w8V9fX9UVFahoaPAwsG/wcC6vLu1t7bBw8K6vLtvcXBPUVBhY2KmqKfBw8K+wL/Iysm+wL+ztbTH yci8vru/wb7T2dWwubS6xsBdbGUgMSlwhXy1zMKzzcKwy8AxTEERLCE/Wk+ct6y40sebsqgsQzmk u7G808lmgHVIYle3zsSqwbcwRz0WKyKInZSrvrasv7c2Rz9AUUmjtKyxwLultK9KVlK2wb23wL24 vrz////////Tsr/SvcbCwsKnvLN5opIKPigIOCI6YU690cWxtq/Hwr/Ev7zBw8K/zsmmxLwwVEgR MSaUrqO3xr+qvbVLdGQZRTSFppm0z8Svyb5hfHEJLR+En5TDycXDw8G1vrm5wr3BwcPFwcTSztGe mp1ycHM/PUCTk5XHx8nCwsS6ury/wcK+wMHGyMltcXJaXF2qrK25u7q/wcC8vr3CxMPFx8a5u7pu cG9wcnHExsWztbTFx8bIysmvsbDAwsHT1dS2uLe4uLbHx8W0uLW8wr64w72MmJIlNi6esamtxLqx y8Clv7RBXFEiPDErRjutx7y1z8SHnJMhNi2ovbSsv7dYa2NyhX2zxLytvrZqeXI8S0S2wry6xsC2 wbuOmZM/SEOwu7W2wr60wLxaZWG3wL29w8G5v73////////UucTHtr7M0M+iua+bxbUGOiQAJQ8v VkOrw7Wjr6XKy8bNzsmstbLA1c6cvbQdQzYRLyWjuK+0v7m0w7xZem0cQjOdt6y3ysKvwLhbcGcT MSWMoZi5ubfCvLy+wL26wLzBw8TExse4uru5u7zHycqBg4RVV1i6vL3EyMm3u7y5vb7CxsfBxcZ6 gIBQVFWhpabDxcS6vLvAwsHBw8K5u7rCxMNnaWieoJ/DxcS/wcC+wL+/wcC9v765u7q8vr3ExsXA wL6/v73Bw8DO0s+yu7aNmJI7SkOcraWswbjG3dOtxLpth3wcMykULiOpwLauw7pjdGwqOTKpuLG5 xb+wvLaXopzDzMe7xL+8wr68wr69wb69wb6/wb6/wb6/wb69wb6+x8Smsa3I08+zvLnGysnDx8b/ ///////Rvsa6r7W8wsCqv7ar0cIvXEgDMBsWPSpzjn+8zsLEzsairKSzwr270sptjoUZOi9LZVy0 w7y8wL25wr1jfnMnRTmWp5+/ysS8x8FhcGkWLSOTpJzPycnNwsS9u7rBxcK4vLu/xcPEyMm3u7rA xMWtsbB+goOGiom6wMDBx8XAxsa1u7nBxcamqqlvc3R5fXy9v769v77Hx8fDxcS6urrBw8KOjo6/ wcC8vLy6vLu9vb3CxMPDw8O+wL++vr7BwcHJx8a/vby+vry7vbqzubWRmpUuOjSwv7iuwbm2ycGz yL+gtaxccWgxRj2VqqGxxLxWYlwtODKgqaS/yMPDycWvs7DExsO4urfAwL7AwL7Bv77Bv77Dv77D v77Dv77AwL67wb+lrquSm5i3vbu+wL+3ubj////////OxcrAvL+7wb+xwrq00sZuk4IsUT8DJRRI ZFWUrJ6ovLGyxLnM4dqOqJ8xT0clQDeVqKLCy8bCwL/GyMWMn5dddGqfqqTFyca9wb5weXQfMCh9 iIK/trfKu767t7bCxMG6wLy5wr3Jz827wb24vrzL0c2wtLN+gn+Giomtsa7IzMu8wL3DxcTExsOa nJt/f326uri6uri+vLu9vbvAvr3FxcOysK/CwsDAvr29vbvAvr3Dw8HGxMPCwsDBv77Bv77GwsG/ u7rDwcC4uLa8wL2Vm5ceKSOirqi7ysOsvbW1xr7A0cmer6dZamJZaGFZZV+Kk5BmbGqlqai8wL/E xsW+vr7CwMHDv8DEvsDEvsDEvsDEvsDEvsDEvsDEvsDBv8C4vryQmZY9Q0Gnq6q9v77CwsL///// ///Bv8LJycvFyci1wLq0xb2txbh0j4AnQzQIJBUrRzhmgXOJpJZjfXQfOTAqQTtvgny+ysa/w8C/ ubnJx8a4x8Cita21u7fDw8HCwsCnq6hicWqIkYy7sLLSw8bBvby9v7zCyMS0u7S9w7++xb62urfA xb/DxcKvsqyHh4Wio57Avr3Cwb2+vLvDwr65tbSloaC3s7LAvr3GwsHGxMPJxcTCwL/GwsG+vLvI xMPCwL/Bvby/vbzCvr3Bv77Dv77Dv77Bu7vCvLzHw8LBwb/DxcKipqNJUk2eqaO+ysSxvbexvbe2 wrzE0Mq+ysSyvbezvLfFy8morKu1t7a8vr2/vb7CwMHAurzNx8nGvcDGvcDGvcDEvsDEvsDEvsDD v8DBv8C9wcCQlpQ3OzqnqajBwcHHx8f///////+0uLnBw8TDxcS+wL25u7jL0suyv7V+koYzT0AZ OikWOCgSMyMKJBs1SkOFlJGyvbm9xsO5u7jBtrjDvb3Ay8XB0Mm+wr+9u7rAvr3KzMmotK6wubTH vL7QwcS6uLe1ubbAxb+3vLW0t7HCxb7Gx8K4ubO+vbnQzcjKxcLGvrvFu7rIvrzHvLvOw8HWyMjD uLeqoaLAvLvHwcHGwsG/ubm0sK/Fv7/Cvr3Evr7Cvr3CvLzAvLvCvLzCvr3Dvb3CvLzCvLzIwsK/ u7rFw8K+vry1ubaorKm9w7+7xL/Cy8bBysWut7Kts6+3vbmwtLHDx8TBx8W8wL+9v77DxcTGxMXG xMW6tLbHwcPEvsDEvsDEvsDDv8DBv8DBv8DAwMC/wcDEyMeutLKKjo29v77AwMC8urv///////+/ xcW4vL2/vb7Mw8TFurzDu7nBwry8yL6rw7V8no07YlAjSDdXcWifsKrDx8jCwsK6vr3CwsDOw8XC ubqyvbe4x8C9wb7Bv77Avr3Bw8Cywbq7xsDGvb7Ct7m7u7nIzce7vrfJysK7urXEw7zV0s3GwbvD u7jLwb2/tLLMvrvMvLzNu7nEsLHHs7LXwcPHtbW8srHIwsK+tbbCvLzJwMHKxMTKwcLLxcXAt7jF v7/LwsPIwsLJwMHHwcHIv8DDvb2+uLjLxcW+urnIxsW+vrzAwr/V19S8wL2ytrO6vrvAxMHKzsvI ysfHyca2trTGyMW4vry/xcO+wsHBw8LExMTBv8C7t7jEwMHDv8DDv8DBv8DAwMDAwMC/wcC9wcC9 wcDFy8m7v76+wL/CxMPEwsPBv8D////////Cy8q8wMHHvsHNvMDSu8HCrrDCt7XFyMG60MO118ah y7iWu6qhu7KtuLS7tbnJwMO9v77Hx8XQxcfHvr+0v7mzwru/w8DEwsHLyci6vru1xr66xsDEwL/H wcG+wr+5wLm3uLDOzMLBvLa+urHBubS+ta7Mwb3GubPKuLbbyMTUu7zRuLbDpqi2mpnPsLPUu7zC tLTUzMrFu7rLw8HIvr3MxMKyqKfMxMLEurnJwb/LwcDBube7sbC8tLLBt7bBube9t7fJw8O+urm9 u7q/v72+wL3ExsOytLHO0M3CxMGsrqvAwL67ubjDwcDAvLvCwsC/xcPBzMi+x8S2vLq8wL+5u7rB wcHCwMHBv8DAwMC/wcC9wcC9wcC8wsC6w8C6w8DAxsS7v764urm9v77EwsPKyMn///////+1trrC wMPOwsbCr7PVv8LQvr/Lw8G6vbexw7iowrezzsO1zMSxvbnDxcTUyc3FtrnDu7jGvLrJtbbRv7/K x8LEw77LwL7Ht7fGuLe+tLLHxr/BvrfHuLPOvbion5ZxaF6/sJ/LuKfDrZ26pJShinynkILYvrHZ vbHPsqavj4RzUUdtSD1kPzJOKBtqRTWDYVWLcGXFrqTRubHKs6magnqLdGpxWVG4oZfSurLSu7HJ sam0nZOpkYmslYu6oprBqqDVvrTVvrTDr6awnpTDtKzIu7K/tazQx8C+trHLxsC/urbPzMi5trLD v77Jw8O8vLqzvri5xb+9yMS1vrvCyMa5vb7GyMm7u73AwMLAwMDAwMC/wb68wr65xby2xry2xry5 v7vIysm5u7rIyMi5ubm8urv////////LucXLucTLusDKu77GvrzAwby6xLy4xL7Bzcups7TIy8+6 t73Dur++srTKv73NvrnXvrnburXVsbDNpqawjIyrh4eRaWq+lJXesbPftrThurXSrKOienBtQzVZ NCJoPylXKAhZJwRmNhJ7Syl1RCZdLBB4Ryu3hmq6iW2LWjyGVTW7i2faq4LBkmaneUqneE5tPBxl NBhrNx9gLxOCTjapeFyFUTlcKw+kcFidbFCRXUV/TjJxPSVoNxtlMRljMBViLA55QyV0QSRaKw9q PiWnf2bSr5vTt6TPuKrSwLTGt6/CuLHPx8TJxMG9ubi9v7y5xr2zxbq3w72+x8S3vb2+wcXJzNG3 uL3BvsTDv8LEvsDBwLy9wrm4xrWxyrSyybW6xLzAwMDAwMDAwMDAwMDAwMD////////KusTKu8LK u77IvbzEv7u/wru5xby2xcCuurjL09WzsLbGu8HPvsLcyMfNurO/p5vEoI6vhXF/VUFpPClkMyR+ SzxrNihsNymNVUahaViQWURpNR17SCu/jWzjsY7ZpX3Gi17kqHblqXnSl2vWmnPSlnGmbEZ4Phl3 QBm3gFfksIHcqXbOm2TWpWrdrW3YpGrLkGS1dVG+flrNjWnlpYHvr4vVlXHRkW2FRSGZWTW3d1PR kW3ion7mpoLion7dnXfZlmzXlGrhoHjeoHmobkljLg5XKAp1TDK6loLKrpvexLfTv7TAr6fDtrDO w7/JxL69vra4vbS+v7nCw766urq4ub3Gx8zKy9DBvsXDvsTGvcLEv7zAwbm6xbWzyLSzyLW8w7zA wMDAwMDAwMDAwMDAwMD///////+6w8C9wb7Ev7zIvbvKvLnHvbnBwLy6w766ycS3yMKotLDT2NLF vLPPu7C9nZCCX0RVMASGXiunf0zLoW/Tp3jlt4jXp3m0gVSjcEGeazuwgUvVpm7itHjRpWbLoF7V qGfMml3cqG7apW/UoWzirn7suIndqXzMmGu8iVzXpHXir3/TpG7Ro2jfsXPesW7Qn2LgpnbIi1/L jmLWmW3anXHQk2fDhlrRlGjZnHDZnHDanXHbnnLbnnLanXHZnHDZnHDgoXXlpnrbnnLNlGnZonvn so7ImHaWaUxrQijAmoXjv63Pr6DEp5uukYeih368oZrKsqrcxLzZxL/ItrTIurrLwsXAu8GysbfB vsXDvsXGvMTGvcDEvr7BwLy9wru9wru/wb7AwMDAwMDAwMDAwMDAwMD///////+yx762xry/wrvG vrnLu7nLu7nGvry/wb6/y8Wjtq7N39SqtaW4sJ+vloBqQSudb03In2nUrG7MpGbTqWzAlFjEllvm tXvXpmzYp2zWpWjUp2bWq2fWrGTSqmDRqV3Tq2HarWnXqmfXqWvZq2/Fll6aazWPYCyoeEegckCW aTSSZS6Wai6VaSqUaSejeDO4i0qeZjGgZDSdYTGQVCSKTh6OUiKMUCCMUCCHSxuFSRmFSRmJTR2O UiKRVSWVWSmXXS2hZzW4gE/QmmvbpXfTn3LLl23NnHTWpoJhMhJiNRh0Ri52SjJnPSlzSTd5Tz9h NihpOS2bbGTDm5PLqqXTu7fQwsHCvLzQztHAv8XAv8XBvsXDvsTEvcTEvsLEvsDDv8DBv8DAwMDA wMDAwMDAwMDAwMD///////+xybyzx7u8w7nDwLnIvbnKvLnIvbzDv762vLi/y8Kuuq7M0b2KfmRl SCrPn33CjWPcrHvMoWrJnmfqvYbmt4PQnmvhr3zSoG3Bj1zBj1qneECLXyOZbzLBmVnMpGS4kUzF n1bOqF/QqWPQqWTJoWGzi02me0KsgUi3jFPGm2LOpGjInmHEm1nLol7Yr2ritXLLlFvco2zco2zR mGHQl2Dbomvgp3DUm2TSmWLLklvHjlfHjlfEi1S7gku0e0SzfESOWyRgLgBSIAB2RA+UYi+ZZjap dkfHk2nEj2fbpn/KlHLBi2vbpIbRmn7FjnLor5a4dWSFRjVpNCZ9U0W+oZfZyMC8tK++vLu9wcK8 wcW9wMe/wMfBvsfGvMfIu8fIu8XDv8LAwMDAwMDAwMDAwMDAwMD///////+2xry4xbu6xLm/wrnD wLvGvrzHvL7HvMDBu73LyMTBwbW4sZ59aUy9m3bHk2nss4XZp3LSo23TpHC8jVmLWSZSIABmMwN9 SxiCUB2AURuWZzG4jVTPpWnOpmnNp2jVsGzTr2XXs2XQrGLKpV7NqGLLpWTOpmjasnXTq27SqGzO pGjOomXVqmjcsW3TqGPGmVbYpGjgqXDco2viq3Lgp2/TnGPZoGjTnGPmrXXdpm3co2vhqnHjqnLb pGvXnmbVoWfRoGXWqGzTpWrEllu6iFGufEWWYy58SRZxOQh1PA6XXDCuc0mjZjyhYzy4elPGhGHu p4ncmX68hWl+VTuIbVbArZzCuazGwrm/wb68wsK5w8W6wse9v8nDvcvKucvKucnDvsTAwMDAwMDA wMDAwMDAwMD////////Gvb7DwLy9wry6xLy5xL68wsDDv8LIu8Tcx9DDrbDSurbQtqddPiKzjGXb p3jNmGLOnGLerXLks3mgbzV7SQ9yQAajcDnYpmzQn2XZq2/crnLPpWbInl/MpGTUr2vVs2zLp1vN qVvQrGLZtG3as27KomLInmHbsXXUqXDQo2rVpm7crnPXqW3KnF7QoGDgrnHirnTcqG/Kk1vPm2LI kVmyfkXFjlbMmF/LlFzBjVTFjlbRnWTcpW3YpGvZomrbqW7PoWPPo2TUqGnarG7bqm3XpmnbqW7i sHXpsnnao2qvdj+gZzC4fUaucTuRVB6RUyDBgVPan3PltoqZdkyPdlDYxKfayrPAtKbEwLe9wry4 xMK1xcW4w8e9v8vGu8vHusnDvsTAwMDAwMDAwMDAwMDAwMD////////Rt8LLusC/wcC4xMCzxsK2 xMTAv8XKusXRtsTRsbrdv7/AoJU/HAFXLQXJlWXkrXXWpGnaqW7Vo2iSYCWygEXaqG3aqG3ToWTd q27aqmrTpmXSp2XXrmzctXDUr2nIo1zUrmXWsGfMpV/Gn1rSqWfXrXDSpmrPomnVpnDXpXDZpnHY pW7VomvOnGLCjlW4hEupdTylczmIUx2EUhiBTBaBTxWrdkC6iE7NmGKpdz2GURt5Rw2ETxmbaS/A i1XerHLZq23YrWvWq2nTpmPSpWTVpWPXp2XYp2XLmljYpWTcqWjYomLZo2Pfp2jfp2jdpWbhqG7R nWPRqHCFZjBUOAl/Yzyig2fDqJXPu7DGv7W6xLy1xsC2xMW6wsfEvMnHu8fDv8LAwMDAwMDAwMDA wMDAwMD////////hus/RtsW9usG3wsS0yMe2xsa/wMfJvMjIsMDbwMvTurvHr6NlRy0/GACxe0/T mWfdqXDTomfgrnNvPQLYpGjXo2fPm1/cq2vaqWnPn13Pol/UqWXQp2PSq2XTrmfOp2LQpWGMXx6B VBN4Sgx7Sg+EUhuNWiXPnGfVoG7Un229hVSUXCuBRxePVSWmajqtc0G0f0u1g0zBjlnRn2jcqXTQ nme1gk2cajN/TBeRXyiHVB95RxCCTxqATheTYCvDkljSpGbUp2TUp2TUp2PTpmPTpmLUp2PVqGTY rGXWqmPSpl3OolnTp17ZrWTZrWTUqF/To12sfzzAmlm5llq4k1+ecUiGTzNmLxuid2nJrqPEwra2 wriywbyzu73Gv8fIvMXDv8LAwMDAwMDAwMDAwMDAwMD////////XrMfPssbCv8i7ycy2zMqyxsW4 vcO9uMHKwMm9t7vAw7q9wKt7dVdCKQOCTibqrYDUoW7aqHPNmmOOXCKeajHgrHLcqGzSnmLgr2/k s3PhsXHRpGHFnFjOp2LTrGfJoF7ImlyreT7AjlTIllzOmWPBjFiQWymXXy5zOgx+QxaXXC+4fVDW mWzgo3ben3PWm27BjluodkGHVSBxPwpwPgl/TRiTYSyfbTjAjlnNm2a+jFevfUizgUyodkGpd0LI ll/TpmXXqmfcr2vfsm7esW3ZrmnUqmLPp1/Dm1PXr2Xhu3DYsmXPqV7PqVzNqVvIoFTcrWewgD2/ mFXOpmnQoG/dn3q6blatX1BjIxdlPTG3r6DJ1MS2yLzCzce6tLbKv8XDv8DAwMDAwMDAwMDAwMDA wMD////////UtMzMucy8vsiwwsKtw8CwxsO6xca9yMnD2NOlxrmr3MSfzqyDn3dLSSBQJAHTl3LK lWvltYfVonOgbDxOGQCteELjr3bZpWzKllzOnF/ZqGvfsnHar23Qp2XSqWfcsHHhr3XRnGbeqXPZ pHDkrHnxuYjVnWzUmmqtckWmaTy0d0rVmGvhpHfKjWCyc0eobUCaZzSmd0O7jFjNnmrYqXXbrHja q3fZqnbWp3PfsHzVpnLQoW3aq3fRom7ImWXXqHDXqmnWqWXUp2PSpWHRpmHRpmHQp2LQqWPctW/K plzAn1TJqFvQsGXPr2LPr2LYsmnUnl6/hEqWZSvVo26xdEiANBSLLBqFJBuqW1JWJBmFfWqvvqmo v6u/0cPAvbm9srTDv8DAwMDAwMDAwMDAwMDAwMD////////PuM3Ivc21w8amw76iyLun0MCu0MCo z72Xz7eF0LGD4rZkwI9jpnNUckFBKwaHWTXbrILRoXPcrHzgrX2PXCeETxnHk1nWombntHXap2bK mVfLm1jXqmbYrWjQpWDPomHeqnHbo3Djq3jSmmfOlmPcpHHXn2zhqXarcUGOVCR5Pw95Pw97QRGD SRmkajrKkl/Vo27WqXLbrHbZrHXWp3HRpG3So23SpW7LnGbRpG3On2nPomvdrnjarXbUpW/ZrXHa r23XrGfUqWTSp2LTqGPTqmbVrGjVrmnPqGPRrGbTrmjQrmfLqWLEolu/nVbEmFmfXy2ua0CueEqb ZjyaWjfgk3nykoTZe3OGPjRTLh5mblaqza+jz7OcwqnJ1cnHyMLAwL7AwMDAwMDAwMDAwMDAwMD/ ///////BsMK+v8avzMed0r6W2LqS2rWDyaRqto9MrX9GvIc3w4QlrmozoF9NkVhOWy9ELgWMZzi9 j13MnWnMmmPQnmPVpGTToF58SgWqdS3SoVXks2baq13aq13brV/Yqlzaq2PapmrZpG7jrnjgq3Xa pW/XomzSnmXcqG/OmmHTn2bZp23cqnDUomjKmF7Nm2HWpWvPoWbPpWjVqWzXrXDbr3LXrXDWqm3R p2rUqGvVq27Tp2rOpGfTp2rQpmnPo2bOpGXLpGHMpWDPpmLTqmbWrWnVrGrQp2XMo2HKoGHYrm/S qGnEmFvPo2bnu37YrG+2gU2pYD+zaU6BSSqcaUrPmH7dnIjtn5NuKB5PJBQuJxAoVDFmr4SP37eS 2LSlzbWqvLC8wr7AwMDAwMDAwMDAwMDAwMD////////FuMS/xMefzrx7yKZmyphfzZJRvYE3qWsl qGYYrmYArFwJsmEZp1s4n1xRg04sMwdrTyhpOxVVJgCod0zcqXrVom+6hk2xfUF0PgCMVhWjcC7F k07frWjRoVvJmVPgr23Vo2jMmmDOnGLZp23erHHZp2zTomXWpWjaqWzYq2rUp2bQo2LRpGPWq2nZ q23VqmjiuXfasW/Qp2XLomDLomDOpWPQp2XRqGbUq2nVrGrUq2nRqGbRqGbVrGrXrmzTrGnTrmjN q2TMp2HMp2PRqmfTq2vUqmvUqGvcrnPYp23Zpm/eq3Tcp3PHj1ymbjuSUyqURjRwIxmmcV/CmYW0 i3dsQjBaJhljOy82LhkwUjFEmmsvomsyqHNAqnpTm3iw2sS4xL7AwMDAwMDAwMDAwMDAwMD///// ///QvMfByseMy65NuIQosWsjvGomvGcasl0Usl0Ktl4AtFcAul4Ls1whqVs5lFExVypTPS1iLys/ DAZqNiuLU0anb1upcFfHjnHdooK3fViNUy6faEHXoHnbpH3FjmfKlmnNmmXMm2DMm2DWpWjZrGvV qGfTqGTQpWDQp2LPp1/Pp1/Rq2LWsGfWsmjSq2XKpFvOpl7QqGDUrGTYsGjctGzbs2vYsGjVrWXN pV3MpFzPp1/RqWHSqmLZsWnZsWnNpmDRsGnMrmbMq2bOrGfTrWzUrG7SpmrOn2eNWiWCShd8QhJ6 Ow9oJwBmIwCYVSvdk3aXR0JoICNMIBlaQDNWRTVFNiVQPjA8Oyc+YUMldEclqnALrGkUt3Qru4A1 n3GIyK2yx77AwMDAwMDAwMDAwMDAwMD///////+3t7mxzMF/1K05vn8JsVwCuloJu1sEtFIAq04E vF4Avl0AtFIAtFcQs1wcnE8vfEYsMiRLKzFLIitEGSJKISdOJypOLCpeODF0RT3CjIDDiHiFSDVx OB17RSV1Px1uOhNyQxd2ShlvQQ9qPQZyQwuQXyS/jk7WpWLcrGbXqGLUqGHTq2PPqGLJpF3KqGDS rWfNoWLOoGTQn2LPnmHOnl7RoF7VpGLYp2TerWrXp2TYqGXVqGXQpWHRpmLGnVuviEWadzWmg0G6 lFPMomXQpGjAkVmmc0OSXjGlcEiwelaudVina1G6emPTkXvKhG+lYVZxMjo3BRAxERQ4JyIhHRI4 QDApPyg6aUc/l2UmpmcCql8AuGkAsGYAol42uoFrzKGa1LuqzLyvyry1x7y6w769wb7///////+m z8GNz7RRw5Abtm4CvmUAwl4AvFgAu1oBtVoAt1wAuV4Aul4AulwAtloMsVcooF5QhWklKylHNUAj DRwdEiIOEh4VJi4OGB8/LjZ/VlzAhYXenpLao4XTonfSo23OpHK+mni3lHm9lHjImnjAi2SqbUGg XiymYyzamF7bm17gpGbgqmzMm16mfD+BXh90SxV3QhqBRCOERiKAQBqHRhyjYTPFg1HdnGfko27a m2beo2zkrHfLmGOebzuJWymOYy6SaTGLXiWBThd7QQ1+QhKMTSKdYD+qcVZzQC9kNStXKilSJCdT ICdYHiphIS9fKjovGi0hFSkkESImFiAlJCAnQy8wdEs0omcXrWECtVwAt1oAt10Ds2ANr2QesW0v tXhCvoRmzZ2I2LGd0ravyrm+yr7///////+Z1L55yqk+uoQUtGoBvWQAwF8AuloEuVwGslwGsV4A tWAAt14AuV4AuVoBtlkTrFwxnGhFgWcnNjE6N0AYGSkKGysAIy4AGSQWIjBIOkmAV2CZZWWaa1mX bEqRbD+Ia0FbRS5gST1yVkaTb1m6i2/NlXK/gFenYzaNRBWbVSKcWSWJSxh9RRSNWiqvg1TPn3m9 hW6+gHG7fGq8fGW+e2Czbk+WUCx7Ng+NSCGpZjyzdEuna0Soc0y1g16idFB9US51SCeQYUGwelrG iWzenILioou5fnCCT0k/GBk2GCIwHCoxIDMwHjQtFy4qEScmEikLCR8VFywjGi0lIiswQTk+c1cu mWERp1sAt1sAu1gAulgAuVoGtF0HsF0Is2QOuGscxHcgtW9CuIB6yqKjzrOrxLH///////+n4cl6 x6dAsn8fsGsRuGYJt14Kr1cQqlYYqVwXqV4PrWAIsV4BtF4AtloCtlcGs1cDqFAopWEkXDcvPC00 MDMWGCIFIysAISgAGSMLIi4vKThFLTtSMTpUNTNONixDNSYgIBMhIxYnIRE1JhFaQCeOa027jWvS nXbTl3LQkGrHhWDLiWbjooLqrY7HjG6TXEV0QjVeLyVOHBFcKRqJUj64fmjRk3rVlnnMjXDIi27A hGi3gGKvfGGcbFN4SjJSJxdYMS5dMzdfLjJkLTJ6QUeLVFpxQkxCIS4gDyEQESUHGCwDHzQAJTcA JjQAKTQMKDQZGCwmGi4jHysgMS0rXEY4kGUmrWoIrloAtlgAtlUDtVcJtlwEtV0As1sAuFwAvWIA umUFsWMhqWtMr4CEv5+p0bn///////+h4MZsu5k3qXYfrmoTtmULtV0OrVkQp1Yap14YqF4QrGAI sWABtVwAt1oAuFcAuVMAwVgPrlJEmV4zUjI1MSguIykFEhoAHigAKDMAKDYNIzUXHDIfGC4iFCkb EyIUEh0QGx8MGhsUHRwfIBojGhE4JhhwVkWqinWpgGy5jHe3hnOcaVh9STxvPDRrODJhODQsEhUo FRkrFRc2HB1JKyhbOjNiPTRgOi97U0lhOS1eOC10T0ZxUEdNLyczFhAwFhocBxseCSYyGDNMLkhX N05KLUMxGzIcEisYHjgHHDUAHTUAHjMAHTAAHCoAICoAISohKzUgJSkdNC4kWEIlgFUamlsIrVwB uVsAt1QAtFMMsVUSsloJs1sAs1gAu1oAwGAAtWAMsGcmqGxIpXiBuJux1L7///////+Cy65QqoQn omwYr2gFtWAAuVwIvGEItl0Kr14Kr2AFsmIAtmAAulwAvFkAvFUAvFIAu08Qr1A5o1tWi10mKRhQ PD0sGiYnJDUBGyoAIDAAIDMAIDYBGzYJGDcPGDcSGzoSHz8IFzYMFzMXHzYXHS8YGCUpJi9FPkVB Njw8MDY+LTVFMz5HNUM7KDkmEyYOBRoPGzMJHjcIGjIAESUCDR8PFyYgIzIpKzcpKTUwLjswMD0r KzghJDMaIDARFykGDScQHEIGEz0DDzMIEzMIES4DDykEFi4MIToAFjEAGTUAHzsHJT8NIjsOHjUU HDEVIy4SLyoURC8haEgrkWIeqmcHsl8AuFYAu1MAu1MDs1EQrVQXrVgRrVoEsFoAvF8Av2YkxHot rXBJqXl+u5mpxbG4v7X///////+JyK5gr41CtIEsvXoGtmMAul0DwmUAul4AtWABtGIAtWIAtmAA uVwAu1kAu1UAvFMArkYBr04WoVBAnmIqSy42LSZWNkE1FigbGCkJHCsAIDAAITQBHDUEGDUJGDcP G0EHFkEIFkMCEToACi4ADS4KGTYQIDkNHjITIjUNHC8NGi8PGTILFTAIDiwNEzUSIEMAFToAG0IA HkQAHkECHz8JIkEJIT0IHTgACiUIHDcPI0ACFzQAEzIGHz4MJUYHIEQDG0UJIUkJHUAFFjQJGDMT ITkOHjUAECcLHTMLHTMOHjUVIDQZHzEfHSsqIy0lNDEbVz0igVUtoGkcqGUIsV4AwGAAxVwAvE4A v1UAtlILrlMTrVcRrlkJr1kDuWIQvWtR15Zr0p+K0qyn0rfByL7Hvbn///////+vzr+Rwqp50KZT z5MVtmgAtl4AwmcAt1sAuGIAtWMCs2MFsmIGsV4GsloIs1UCtlUAwmIAu14CwGgIn1gwhlkbNB9W Nzo9CRZaMUFGKzowKDUmJjIhHi8XFigOFCYKFC0ADTULHEgRJ1ANJUsEIUEBIDwAHjYAFy0AGCsA HjEAIjgAHzcAGDQAGDYDHEAGIkkCIk0AH00AGkYAFUAAFj4DGUACFTsAEDMKHkEEGzsEGz0FHUEA GT8AFDkAGT8IIUUBETIOFDIVFS8ZEigoGiw9KDlDKDk7IDE+JjY3IzEsHykmHSIfHBgdHxQnLBob RCQnlFsfsWobtmoGrFgAq1AAulYAwlgAvlAAw1UAvFIAtlQHtFgKsVkMrlkQs2IgtGpYy5KH3rOo 48Ox0bzAv7jRwcH///////+4zMGkybeU3Ldp1p8gtGwDs2ADxGsAuGAAt2MAtWUFsWUJr2MMr2AM sFoMsVcIs1kAtmAArlkAvmYAtGIorW5Ck2Y7WD5aW0syMiUrKR8oJR42LCpINTlKO0BFQ0ZESFE/ QVouMVAoL0srN08iM0cNIzMFHCoJIzAAGSQKIS8KIDAFFigLFiwZHzkWGjcICywKDjMQFDoSFjsR FDcTEzUWFjYXGDYTFzIPFS8LEiwJEywNGTMSITwYKUMaLkkeMEgkMkEkLTYqLzMzNTQrKiUcGhAc GA8nJRkVFwwaIhUlNiQzTTQ7Xz1CbERNf05Dl1kaqFoBrVUCrlYJtlwGuFoAtFIAtU8AulIAwVYA v1QAvVYAvVsCtlsHsVsQrl8fr2k9tHxXuIt/x6Sm0bu6x727urX///////+vyb6s1sKP1bNZwI0k r2wKsWMAuWcAvmsDvG4QwnYawnkavHMYu24WvmkOvWIJtFoUqmASrGQEtmQAtmADsFwNq1wbqFwo pl0tol44k1hFdUtHVDhINihBKR83LyA5MidMNjZZPEBYP0JNNzdEMC9GNTBMOzZPPDhNODVTNzZc OT1nPENsOERrLj1pJjhlJjlsPE5kOk1fNkZZMD5UKzdPKjJMKTBJKi9PMjZILzJALC03JygvJCMp ICEmICIgIh8RIxURLhgZPR8hUSkqZDQwdD8zgkkxi04ylFcyml0vnV4roForpFkrqVgmp08ZpkoR tloEs1YGrVMLrlUSsFcQs1gKtVcAuVgAvlgAw1oAw1sAwlsAvl4AuGAKs2ATr2UZrW4ssXpTwZKD 1LGl1sGqzLz///////+pvLaryruay7NzvZhNtIE6t3swv38swIE1xYg9x4xHyJBHyI86xYIlvXAM tl4Eq1MXpVkYploHsVkAt1gAulYAvFQAvVIAvFIAu1UQrlUvmlRIiVNceFJdcFBPc01OckxHVzVR WDdPWTZGVTBDVC5GVjJIWDRHVTI/SCc9QCE+OB5CNBxEKxdCIRBDHA1EHhEvFQgrGAkrGAksGwkv IAswJQ8yKxEzLxQ3Oh03Ph85RCQ7TCpBVjVHYD5OaUhKck1DflI5hVI4jlE1llEvnlEqpFElqVUg rFYYqlcXr1wSsFsJrlYFrlEGtFIFuU4EulAEuVUFtFUJslUSsloYsFsYrlsRqVYHqVQDtlsAu10A vF4AvF0AuF8Asl4Kq18Qp2APo2UhqnRJvY5506+a2MGh0L7///////+/v8HHycbCzsSxyLadxauV yquQ0K6Mz66V1LeX07md17yZ37182KlOxYclumsUt14Rr1IOr08EtU0Auk4Avk8AwVAAwk4AwU4A xVQAvVMJslcdq10wqGYxqGgiqGUdpForoFIvn00snU0nnEsnoU4ppFMnolIinU0wqlotolQtmU4v lUwxkUoxi0Y3ikY9jEszeD01eT41ej83fkI3hEM6iUg6j0w6lE88nFU3nVQynVIunVErnVMqoFQp olUlpVgfqlsZrVsYrlcYr1QUrVATrE8Tqk8SqFEUqVgWr18SsGEGrVsAr1YAt1YAvlYAvlQAuFUG uFoMu14TvGMdumckt2kqsWopr2ortHAkuHAbuG8XuW4WtmwasWojq2knp2wup3I/rIBhvZiH0LOj 08GozsH///////++ub/Dv8LHwcHCv7q/wLi9yLq5ybyzx7u6ysC4x8C9z8S118SIy6dIsHkYql8M tVoJulIEuEsBt0kAuEsAu08Av1AAwVEAwFEAxVkAvlYAs1QArVcErVwGr2AAsGAAsFoPtVYRs1AP s1INtVMNuVcLu1kGulkDt1YAs1IAsFACsVIJtFYMtFUMsFEOr1EYr1Qiq1YnqFYkqFUiqFQfqFMe qlQbq1QYr1UbtlsWtVkRtVcMtFUJtVQGtFMFtFUDtVcAsFUAsFUAslMAtVAAtVAAtVAFslQIsVgJ rFsNsGMMsmYEs2QAuGMAvWAAwFsAvVYAuVkCulwFvGANvmYhwnQ8yYRYy5BoypdpxZZnxZVfxpZY x5JVyJFVxI9cwI5gu49vv5p7wKOQyLCm0MC0z8a0x8H///////+0vsC4vcC/u7zAt7jCurjDvrq/ wLu8vrvAvr+8vL69w8GtybtzuZcun2kAoVUAtVcAvFIAvE0Atk0As04AtFAAtFUAtlcAtVgAtl8B tGACsmEBsGECsWQGsmYJs2gOtWcIqlULq1ULrVgJr1sDrlsAsFwAsVwAtGAAuWQAuGIAumEAvWIA vF8AuFkAt1YAtlgJsVoNr1oMsFwLsV0Ksl0KtF4Itl8GuWAArFMArlQAsVYAtFgAuFsAvF4AvmMB vWQEtmQFtWIAuF0Au1sAvlgAv1kAvlwAvGAAuGIAtmYAs2gAsmcAuWYAv2gAwGIAuFoAuVsAt1sA tlwAtWIevnZO0JR+2a6d2rukz7apzLajzrie0LWa07WZ0rSdz7KkzLSvx7e3xLq+xb7FxcPHwcPG u8H///////+/ydDBxsrHwMfJvcHMvcDKv8HGwsHDwcLJxMrFwMbDxMivycB5u501p3MHq2AAvmMA ulgAuVsUs2EermQgrWYdr2gXtGsYtW4ZrGohrW4os3Qot3UfuXMVtW0NsWYJrmELsV0KslsKs2AK tWQEtGMAsGAAtGQAuWkAumgAtmMAtF8At18At10AtlcAt1YAuloAslUAsVYAslkAtFoAtVsAtl4A tl4AuGEAvmYAvmYAvmUAvWQAvGMAu2AAumEAt2ACsWQDr2EAs10At1kAuFYAulcAuVkAuF4Au2gD uGsAsGcAq2IArmEAtWIAuF8AtVoAtl4AtF8AsFwBrWEnt3lgzJ2X07e3z8HBwr3FwL3Aw727x760 yr20zLy4yry9x7zBwLvHvbzIvL7Ku77KucHKucH///////+8wMu/vsbGucPKucHJur/Eu769v8C7 wMO9wMe7vMO6vcKsxr+ExKlKuIcYuG4DvGoIwHUmwoNXvJJvuJhuuZpivJlPx5pPypxSvZNfuZNt uZNtvpNZxIw8wn0cumsDtFoEuVwAtVQAsVQAtFkAs1sAsVsAsFwAsWAAtGMAs2AAtWAFuWAGul8D t1oDt1YFuVgCulgCulgCuloCuloBuVkBuVsAuVoAt1oAslYAslYAslcAs1gAs1gAtFcBslgDsVoJ sWYJsWYDs2IAtF0At1oAuVoEt1wLtGEevHEpwHkuwX0lunYYtmsPtmQIuV8Gt10SuWkWuG0Vt24j tXZOwI+Dzq+wyr/Eu77Qsr7Rsb7It73AvL26wLy4wrq9wLnAv7q8vbe+v7rBv77Avr2/vcDAvsH/ //////+9vce/vMXIvMXPwMfNwcXHwcPBw8TAxci7wMS4u8C7vsO4y8ej0757yqhJv4ovtnw8wI9f yaWWy7uxz8evz8ai0cOP2MSN3cSa28Wi076rzLmq0LeZ2rR+16VXzpA4xXwavmoEt1wAsVYAuVsA vWIAumIAtV8AtV8AtmEFt2MSu2gdwG8gvWwWsmELqlYDqlIDslMAtFMAtlYAt1YAuFkAt1gAtVkA s1oNt2ERtGMVsWMVsGIXr2IWrGAUrF8UqmIcr20XrW0QrWYIr2EDrl0FrlsKq1sRp106wH9Vz5Rp 3KVl1p5SyIxAvXs1uXAytW87snhDtYFIuIZavZGAy6yr1sPEysjJtr7Yt8TYt8TPvMTIv8LCwsLC wsDFwr7Fwr6/wLvAxMHExsPAxMPAwsG+wsP////////Av8TAwMLDv8LDv8DDv8DBv8DAwMC/wcK/ wcK/wcK/wcK8wsC2xb6vyb6nzryj0Lyjz76ozMC1xsC5xMC5xMC2xcCvycKuycCyx8C1xr65xL64 xbyyyLusy7unzrmW17dWwpArvnoGt2cAt2EAu2IAu2AAt1wAtVwAuV8AtWAZum49yYZPzJBBvoQi sHMTrWcPsmEItFwCtl0At14AuWAAumEAuGQIsmUiuXY1uoBGv4pNv45JuYlCs4U7sIE7sIE/r388 sX0ytn0ouHocuHYVtW8WrWobpWk8rnpsy5+T37mY2LaW0bCe2bid27aX0K+kz7mnzryozbyrzLyv yb62xb6/wcDEvsDHvMDHvMDEvsDBv8DAwMDAwMDBv77Bv77AwL6/wcDAwMC/wcDAwMC/wcD///// ///AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCyx76Qz7JVv5EZrW4ArmIAtmMA vmcAumIAt18AuWEDsF4jsm5Yy5SA27B/1rFeyaBGwI8yt3Yktm0TsWYGrV8ArF0Ar2INsWoernBe 16Rz2K6H27mR3L6P2cCK1ryE172H17qa4cOU3ruA2rRp1aZQypk/vok3r386pHZktZKMx6ms0b2z yriywrW6x7i7yLy3w7m/wb7AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD////////AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMC6w7681MaMxadOtYYkrnIRrmcHsGEGr14HsF8Er14RrGI9s3l1yqCk276t2MKa0rqI za50zJ5jyJBNvoQ6tHkrrXEoqXAvpXA6oXKA0KuR0LOi0ryr0sCq0MOm0MKj08Op08Ozy720yrup 0L2f1buV17uN1raP0bWUzLGcvq2xwbTEw77JvrrJubnJubfLvbzHv7zDv77AwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD////////A wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwL7Exb+wyLiGzqtbxZUysncWol8S olwaqmQirms6tnhpwpSUy6yxybm2w7mwx72u0L+m1Lia1rKM06t9zaVvxpxlvJJhsYxnqIidyrOr x7i2xry6w764wby1wb2xxL63w73BubfDube8wbu2yLyvzr+s0b+v0MC2zL+9xL3FvbrOurzWub3V uL3OtbjMuLrMvr7Dv77AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMD////////AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDBv77BvLm7x72k1b2G1rFjxpdItYBEsXpOtoFjx5N3yp6Yza+wzLi9wru9u7q5wr+7ysO1 xbi1yrmw0Luq1byk1Lyez7ecx7Ogv6+6yr/FxsHMwsHOv8LMvcDIvb/Fv8HHvsHVvsTUvsHLwMLC w764xL6yxLmxwLm2vbbHw8LJu7vNtrzTur7RvMHJu7vEu7zEwL/Bv8DAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMD////////AwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDBv77JvsC7wLmizLiV2LeI3bR92q181ad9 06aR4LWZ1rSnyrK4xbnIw8DLwsPAwsO5v73Av7q+wbi5xbmzybqwzL2vzr60zL+5yb/Av7vHvLvO t73QtbzPtbzNtrzJuL7Mub/Ts7zTtb3Nur7Fv7/Bw8C9xsHBxcLFxcPIvb/JuLzNtrzQub/OvcHI vb/Avr2/wb7AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDA wMDAwMDAwMDAwMDAwMDAwMD///////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////8ADAEAAAMAAAABAGgAAAEBAAMAAAABAGgAAAECAAMAAAAD AAB/XgEDAAMAAAABAAEAAAEGAAMAAAABAAIAAAERAAQAAAABAAAACAESAAMAAAABAAEAAAEVAAMA AAABAAMAAAEXAAQAAAABAAB+wAEcAAMAAAABAAEAAAFTAAMAAAADAAB/ZIdzAAcAAAwYAAB/agAA AAAACAAIAAgAAQABAAEAAAwYYXBwbAIAAABtbnRyUkdCIFhZWiAH1QAFAAkAEAAMACFhY3NwQVBQ TAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9tYAAQAAAADTLWFwcGzXg3Yy7S7TRRyAjhd6BEJv AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5yWFlaAAABLAAAABRnWFlaAAABQAAAABRi WFlaAAABVAAAABR3dHB0AAABaAAAABRjaGFkAAABfAAAACxyVFJDAAABqAAAAA5nVFJDAAABuAAA AA5iVFJDAAAByAAAAA52Y2d0AAAB2AAAAxJuZGluAAAE7AAABj5kZXNjAAALLAAAAGRkc2NtAAAL kAAAAC5tbW9kAAALwAAAAChjcHJ0AAAL6AAAAC1YWVogAAAAAAAAYyoAADcLAAAE+1hZWiAAAAAA AABtGwAAsPAAAB79WFlaIAAAAAAAACaRAAAYIAAAryxYWVogAAAAAAAA81IAAQAAAAEWz3NmMzIA AAAAAAEMQgAABd7///MmAAAHkgAA/ZH///ui///9owAAA9wAAMBsY3VydgAAAAAAAAABAc0AAGN1 cnYAAAAAAAAAAQHNAABjdXJ2AAAAAAAAAAEBzQAAdmNndAAAAAAAAAAAAAMBAAABAA4TFxocHyEi JCYnKSosLS4vMDEzNDU2Njc5Ojs9Pj9AQUNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltbXF1eX2Bh YmJjZGVmZ2doaWpra2xtbm9vcHFyc3N0dXZ2d3h5enp7fH1+fn+AgYKCg4SFhoeHiImKi4yMjY6P kJGRkpOUlZaWl5iZmpqbnJ2enp+goaKio6SlpaanqKmpqqusrK2ur6+wsbKys7S1tba3uLi5uru7 vL2+vr/AwcHCw8TExcbGx8jJycrLzMzNzs/P0NHS0tPU1dXW19jY2drb3Nzd3t/g4OHi4+Tl5ufo 6err7O3u7/Dx8vP19vf4+vv9/wAJDRASFRcZGx0eICEjJCYnKCorLC0uLzAxMjQ1Njc5Ojs8PT5A QUJDREVGR0hJSktMTU5OT1BRUlNUVVVWV1hZWlpbXF1eX19gYWJjY2RlZmZnaGlqamtsbW1ub3Bx cXJzdHR1dnd3eHl6ent8fX5+f4CBgoKDhIWGhoeIiYqKi4yNjo+PkJGSk5SUlZaXmJmZmpucnZ6e n6ChoqKjpKWmp6eoqaqrq6ytrq+vsLGysrO0tba2t7i5urq7vL2+vr/AwcLCw8TFxsbHyMnKysvM zc7Oz9DR0tLT1NXW19jY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7vDx8vP19vj6/P8ACg0QEhQWFxka HB0eHyAhIiMkJCUmJygoKSssLi8wMTM0NTY3ODk7PD0+P0BBQkNERUZHSEhJSktMTU5PUFBRUlNU VVVWV1hZWVpbXF1dXl9gYWFiY2RlZWZnaGhpamtrbG1ub29wcXJyc3R1dXZ3eHl5ent8fX1+f4CB gYKDhIWFhoeIiYqLi4yNjo+QkZGSk5SVlpeXmJmam5ydnp6foKGio6OkpaanqKmpqqusra6vr7Cx srO0tLW2t7i5ubq7vL2+v7/AwcLDxMTFxsfIycrKy8zNzs/Q0dHS09TV1tfY2drb3N3e3+Dh4uPk 5ebn6Onr7O3v8PLz9fb4+vz/AABuZGluAAAAAAAABjYAAJysAABYEAAAUm4AAI4UAAAnbQAAFqgA AFANAABUOQACMzMAAfrhAAHXCgADAQAAAgAAAAAAAAAAAAAAAAABAAEAAQABAAIAAgACAAMAAwAE AAYABwAJAAsADQAQABMAFgAbACAAJQAuADcAPgBFAE0AWQBlAIEAkACfALAAwQDlAPgBCwE1AUsB YQGQAcEB9QIrAmQCgQKfAtwDHANfA+oEDwQ0BH8EzQT1BR0FcAXEBhsGdAahBs8HLQeMB+4IUgi4 CSAJign2CmQK1QtHC7wMMgyrDSYNog4hDqEPJA+pEC8QuBFDEc8S7hOAFBUUqxVDFd0WeRe2GFgY /BmhGkgbnBxJHPgdqB8PH8UgfSE3IrAjbyQwJPMmfidGKBApqSp5K0osHC3HLqAveTBVMhIy8zPV NLk2hzdxOFw5STo4PBo9Dj4DPvs/9EHqQuhD6ETpRexH90j/SglLFEwhTkBPUlBmUXtTq1TFVeFW /1k/WmFbhVyrXvtgJWFSY69k4GYSZ0dptGrtbChuom/hcSJzqXTvdjZ4yXoVe2N+A39VgKmDVoSv hgmIwoohi4GOR4+skRKT5JVQlryZm5sMnfSfaqDho9WlUabPqc6rUazUr+CxabLytgu3mbkpvE29 4b93wqfEQcXdx3vKusxbzf/Po9Lx1JvWRdfx2Z/bTtz/3rHgZOIZ49DliOdB6Pzquex27jbv9/G5 8przfPVC9wj40Pm1+pr8Zf1L/jH/GP//AAAAAAAAAAAAAQABAAEAAgACAAMABQAGAAgACwAOABIA FgAdACUAKwAxADcAQgBNAFkAZQBzAIEAkACfAMEA0gDlAQsBIAE1AWEBeAGQAcEB9QIPAisCZAKf AtwDHANfA4ED6gQ0BFkEfwTNBR0FcAWaBcQGGwZ0Bs8HLQeMB70H7ghSCLgJIAmKCfYKZArVC0cL vAwyDKsNJg2iDiEPJA+pEC8QuBFDEc8SXROAFBUUqxVDFd0XFxe2GFgY/BmhGvEbnBxJHPgeWx8P H8UhNyHyIrAjbyTzJbcmfigQKNwpqSp5LBws8S3HL3kwVTEzMvMz1TS5Noc3cThcOUk7KDwaPQ4+ Az/0QO5B6kLoROlF7EbxR/dKCUsUTCFNME5AUGZRe1KSU6tUxVb/WB5ZP1phW4Vd0l77YCVhUmJ/ ZOBmEmdHaHxq7WwobWRuom/hcmVzqXTvdjZ4yXoVe2N8sn9VgKmB/4SvhgmHZYjCi4GM445Hj6yS e5PklVCWvJmbmwycf530oOGiWqPVpVGoTqnOq1Gs1K/gsWmy8rR+t5m5Kbq6vE2/d8EOwqfEQcXd x3vKusxbzf/Po9FK0vHUm9ZF1/HZn9tO3P/eseBk4hnj0OWI50Ho/Oq57HbuNu8W7/fxufN89UL2 JfcI+ND5tfqa+3/8Zf1L/jH+y/9l//8AAAAAAAAAAAABAAEAAQACAAIAAwADAAUACAALAA4AEgAW AB0AJQAuADcAQgBNAGUAcwCBAJ8AsADBAOUBCwE1AWEBkAHBAfUCKwKfAtwDHANfA+oEDwQ0BH8E pgTNBR0FcAXEBe8GGwZ0Bs8HLQeMB+4IUgiECLgJIAmKCfYKZArVC0cLvAwyDKsNJg2iDiEOoQ+p EC8QuBFDEc8SXRLuE4AUqxVDFd0WeRcXGFgY/BmhGkgbnBxJHPgdqB8PH8UgfSE3IrAjbyQwJPMm fidGKBApqSp5K0os8S3HLqAveTEzMhIy8zS5NaA2hzhcOUk6ODsoPQ4+Az77P/RB6kLoQ+hE6Ubx R/dI/0oJTCFNME5AT1JQZlF7U6tUxVXhVv9YHlk/W4Vcq13SXvtgJWFSY69k4GYSZ0dofGm0au1t ZG6ib+FxInJldO92Nnd/eMl6FXtjfgN/VYCpgf+DVoSvh2WIwoohi4GM44+skRKSe5PklVCYK5mb mwycf530n2qiWqPVpVGmz6hOq1Gs1K5ar+CxabLytgu3mbkpurq8Tb3hv3fCp8RBxd3He8kZyrrM W83/z6PRStLx1JvWRdfx2Z/bTtz/3rHgZOIZ49DliOdB6Pzp2uq57HbuNu8W7/fxufKa83z1QvYl 9wj40Pm1+pr7f/xl/Uv+Mf7L/2X//wAAZGVzYwAAAAAAAAAKQ29sb3IgTENEAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAG1sdWMAAAAAAAAAAQAAAAxlblVTAAAAEgAAABwAQwBvAGwAbwByACAATABDAEQA AG1tb2QAAAAAAAAGEAAAnCAAAAAAuHuWgAAAAAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENvcHlyaWdo dCBBcHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAA= X-ABUID:507EA5A9-B64C-4726-A43D-79771CE68EE7\:ABPerson END:VCARD Text-vFile-asData-0.08/examples/0000755000175000017500000000000012101467724016565 5ustar richardcrichardcText-vFile-asData-0.08/examples/Text-vCard/0000755000175000017500000000000012101467724020546 5ustar richardcrichardcText-vFile-asData-0.08/examples/Text-vCard/full_card_v2_1.vcf0000644000175000017500000000126312101464332024022 0ustar richardcrichardcBEGIN:VCARD VERSION:2.1 N:Person;Test,Given;;; FN:Test Person NICKNAME:Wibble,Wobble ORG:Company; TITLE:Job Title EMAIL;HOME:email\@domain.com TEL;CELL:+7112345 23456 TEL;HOME:02085123123 TEL;WORK:02073441234 TEL;WORK,PREF:02071231234 ADR;HOME,PREF:;;Two line street address\nSecond line;London;County;Post CodeW1H;United Kingdom ADR;WORK:;;First work address - street;Work city;London;Work PostCode;CountryName ADR;HOME:;;Parents address;City;Country;PostCode;Country ADR;WORK:;;Second work address - street;2City;2Country;2PostCode;2Country NOTE:A note\nwith return GEO:51;23 URL:leo.cuckoo.org BDAY;value=date:1975-04-19 X-AIM;type=pref:123123 X-ICQ;type=WORK;type=pref:12341234 END:VCARDText-vFile-asData-0.08/examples/Text-vCard/evolution.vcf0000644000175000017500000000020212101464332023254 0ustar richardcrichardcBEGIN:VCARD VERSION:2.1 X-EVOLUTION-FILE-AS:Sister FN:Sister N:;Sister TEL;HOME:345234534 234 UID:pas-id-3EDER42342390 END:VCARD Text-vFile-asData-0.08/examples/Text-vCard/simple.vcf0000644000175000017500000000044512101464332022532 0ustar richardcrichardcBEGIN:VCARD VERSION:2.1 N:T-surname;T-firstname;;; FN:T-firstname T-surname TEL;TYPE=HOME:020 666 6666 TEL;TYPE=CELL:0793 777 7777 ADR;TYPE=HOME:;;Test Road;Test City;;Test Postcode;Test Country ADR;TYPE=HOME,PREF:;;Pref Test Road;Pref Test City;;Pref Test Postcode;Pref Test Country END:VCARDText-vFile-asData-0.08/examples/Text-vCard/phone_v1.vcf0000644000175000017500000000033512101464332022756 0ustar richardcrichardcBEGIN:VCARD VERSION:1.0 REV:20030714T231336 FN:Blogs, Joe N:Joe;Blogs ADR:;;The street;The City;;Postcode;Country TEL;HOME:4534345645 TEL;CELL:2563456456 EMAIL;INTERNET:joe@domain.com URL:http://www.domain.com/ END:VCARD Text-vFile-asData-0.08/examples/Text-vCard/full_card_v3.vcf0000644000175000017500000000126312101464332023603 0ustar richardcrichardcBEGIN:VCARD VERSION:2.1 N:Person;Test,Given;;; FN:Test Person NICKNAME:Wibble,Wobble ORG:Company; TITLE:Job Title EMAIL;HOME:email\@domain.com TEL;CELL:+7112345 23456 TEL;HOME:02085123123 TEL;WORK:02073441234 TEL;WORK,PREF:02071231234 ADR;HOME,PREF:;;Two line street address\nSecond line;London;County;Post CodeW1H;United Kingdom ADR;WORK:;;First work address - street;Work city;London;Work PostCode;CountryName ADR;HOME:;;Parents address;City;Country;PostCode;Country ADR;WORK:;;Second work address - street;2City;2Country;2PostCode;2Country NOTE:A note\nwith return GEO:51;23 URL:leo.cuckoo.org BDAY;value=date:1975-04-19 X-AIM;type=pref:123123 X-ICQ;type=WORK;type=pref:12341234 END:VCARDText-vFile-asData-0.08/examples/Text-vCard/README0000644000175000017500000000005612101464332021417 0ustar richardcrichardcFiles copied from Text::vCard's t/ directory. Text-vFile-asData-0.08/examples/Text-vFile/0000755000175000017500000000000012101467724020554 5ustar richardcrichardcText-vFile-asData-0.08/examples/Text-vFile/README0000644000175000017500000000005612101464332021425 0ustar richardcrichardcFiles copied from Text::vFile's t/ directory. Text-vFile-asData-0.08/examples/Text-vFile/03_multi.dat0000644000175000017500000000365212101464332022700 0ustar richardcrichardcBEGIN:VFILE VERSION:3.0 ADR;type=HOME;type=pref:;;123 Disk Dr.\nSuite 101 \ side door;Ottawa;Ontario;K1Y 2E9;Canada ADR;type=WORK:;;74 Bayswater Ave;Ottawa;ON;K1Y 2E9;Canada ADR;type=WORK;type=pref,transient;codething=4829394:;;456 Lazy Lane;Ottawa;ON;K1Y 2E9;Canada PHOTO;encoding=b;type=png:leo's_nice_picture_here END:VFILE BEGIN:VFILE VERSION:3.0 ADR;type=HOME;type=pref:;;123 Disk Dr.\nSuite 101 \ side door;Ottawa;Ontario;K1Y 2E9;Canada ADR;type=WORK:;;74 Bayswater Ave;Ottawa;ON;K1Y 2E9;Canada ADR;type=WORK;type=pref,transient;codething=4829394:;;456 Lazy Lane;Ottawa;ON;K1Y 2E9;Canada PHOTO;encoding=b;type=png:leo's_nice_picture_here END:VFILE BEGIN:VFILE VERSION:3.0 ADR;type=HOME;type=pref:;;123 Disk Dr.\nSuite 101 \ side door;Ottawa;Ontario;K1Y 2E9;Canada ADR;type=WORK:;;74 Bayswater Ave;Ottawa;ON;K1Y 2E9;Canada ADR;type=WORK;type=pref,transient;codething=4829394:;;456 Lazy Lane;Ottawa;ON;K1Y 2E9;Canada PHOTO;encoding=b;type=png:leo's_nice_picture_here END:VFILE BEGIN:VFILE VERSION:3.0 ADR;type=HOME;type=pref:;;123 Disk Dr.\nSuite 101 \ side door;Ottawa;Ontario;K1Y 2E9;Canada ADR;type=WORK:;;74 Bayswater Ave;Ottawa;ON;K1Y 2E9;Canada ADR;type=WORK;type=pref,transient;codething=4829394:;;456 Lazy Lane;Ottawa;ON;K1Y 2E9;Canada PHOTO;encoding=b;type=png:leo's_nice_picture_here END:VFILE BEGIN:VFILE VERSION:3.0 ADR;type=HOME;type=pref:;;123 Disk Dr.\nSuite 101 \ side door;Ottawa;Ontario;K1Y 2E9;Canada ADR;type=WORK:;;74 Bayswater Ave;Ottawa;ON;K1Y 2E9;Canada ADR;type=WORK;type=pref,transient;codething=4829394:;;456 Lazy Lane;Ottawa;ON;K1Y 2E9;Canada PHOTO;encoding=b;type=png:leo's_nice_picture_here END:VFILE BEGIN:VFILE VERSION:3.0 ADR;type=HOME;type=pref:;;123 Disk Dr.\nSuite 101 \ side door;Ottawa;Ontario;K1Y 2E9;Canada ADR;type=WORK:;;74 Bayswater Ave;Ottawa;ON;K1Y 2E9;Canada ADR;type=WORK;type=pref,transient;codething=4829394:;;456 Lazy Lane;Ottawa;ON;K1Y 2E9;Canada PHOTO;encoding=b;type=png:leo's_nice_picture_here END:VFILE Text-vFile-asData-0.08/examples/Text-vFile/02_simple.dat0000644000175000017500000000050712101464332023032 0ustar richardcrichardcBEGIN:VFILE VERSION:3.0 ADR;type=HOME;type=pref:;;123 Disk Dr.\nSuite 101 \ side door;Ottawa;Ontario;K1Y 2E9;Canada ADR;type=WORK:;;74 Bayswater Ave;Ottawa;ON;K1Y 2E9;Canada ADR;type=WORK;type=pref,transient;codething=4829394:;;456 Lazy Lane;Ottawa;ON;K1Y 2E9;Canada PHOTO;encoding=b;type=png:leo's_nice_picture_here END:VFILE Text-vFile-asData-0.08/examples/rfc2445-objects/0000755000175000017500000000000012101467724021305 5ustar richardcrichardcText-vFile-asData-0.08/examples/rfc2445-objects/4.6.5-timezone-2.ics0000644000175000017500000000062012101464332024434 0ustar richardcrichardcBEGIN:VTIMEZONE TZID:US-Eastern LAST-MODIFIED:19870101T000000Z TZURL:http://zones.stds_r_us.net/tz/US-Eastern BEGIN:STANDARD DTSTART:19671029T020000 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 TZOFFSETFROM:-0400 TZOFFSETTO:-0500 TZNAME:EST END:STANDARD BEGIN:DAYLIGHT DTSTART:19870405T020000 RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 TZOFFSETFROM:-0500 TZOFFSETTO:-0400 TZNAME:EDT END:DAYLIGHT END:VTIMEZONE Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.6-alarm-3.ics0000644000175000017500000000061312101464332023702 0ustar richardcrichardcBEGIN:VALARM TRIGGER:-P2D ACTION:EMAIL ATTENDEE:MAILTO:john_doe@host.com SUMMARY:*** REMINDER: SEND AGENDA FOR WEEKLY STAFF MEETING *** DESCRIPTION:A draft agenda needs to be sent out to the attendees to the weekly managers meeting (MGR-LIST). Attached is a pointer the document template for the agenda file. ATTACH;FMTTYPE=application/binary:http://host.com/templates/agen da.doc END:VALARM Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.5-timezone-3.ics0000644000175000017500000000060412101464332024437 0ustar richardcrichardcBEGIN:VTIMEZONE TZID:US--Fictitious-Eastern LAST-MODIFIED:19870101T000000Z BEGIN:STANDARD DTSTART:19671029T020000 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 TZOFFSETFROM:-0400 TZOFFSETTO:-0500 TZNAME:EST END:STANDARD BEGIN:DAYLIGHT DTSTART:19870405T020000 RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=19980404T070000Z TZOFFSETFROM:-0500 TZOFFSETTO:-0400 TZNAME:EDT END:DAYLIGHT END:VTIMEZONE Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.4-freebusy-1.ics0000644000175000017500000000026112101464332024425 0ustar richardcrichardcBEGIN:VFREEBUSY ORGANIZER:MAILTO:jane_doe@host1.com ATTENDEE:MAILTO:john_public@host2.com DTSTART:19971015T050000Z DTEND:19971016T050000Z DTSTAMP:19970901T083000Z END:VFREEBUSY Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.6-alarm-4.ics0000644000175000017500000000026512101464332023706 0ustar richardcrichardcBEGIN:VALARM TRIGGER;VALUE=DATE-TIME:19980101T050000Z REPEAT:23 DURATION:PT1H ACTION:PROCEDURE ATTACH;FMTTYPE=application/binary:ftp://host.com/novo- procs/felizano.exe END:VALARM Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.5-timezone-4.ics0000644000175000017500000000101612101464332024436 0ustar richardcrichardcBEGIN:VTIMEZONE TZID:US--Fictitious-Eastern LAST-MODIFIED:19870101T000000Z BEGIN:STANDARD DTSTART:19671029T020000 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 TZOFFSETFROM:-0400 TZOFFSETTO:-0500 TZNAME:EST END:STANDARD BEGIN:DAYLIGHT DTSTART:19870405T020000 RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=19980404T070000Z TZOFFSETFROM:-0500 TZOFFSETTO:-0400 TZNAME:EDT END:DAYLIGHT BEGIN:DAYLIGHT DTSTART:19990424T020000 RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=4 TZOFFSETFROM:-0500 TZOFFSETTO:-0400 TZNAME:EDT END:DAYLIGHT END:VTIMEZONE Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.1-event-2.ics0000644000175000017500000000037212101464332023723 0ustar richardcrichardcBEGIN:VEVENT UID:19970901T130000Z-123402@host.com DTSTAMP:19970901T1300Z DTSTART:19970401T163000Z DTEND:19970402T010000Z SUMMARY:Laurel is in sensitivity awareness class. CLASS:PUBLIC CATEGORIES:BUSINESS,HUMAN RESOURCES TRANSP:TRANSPARENT END:VEVENT Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.4-freebusy-2.ics0000644000175000017500000000054712101464332024435 0ustar richardcrichardcBEGIN:VFREEBUSY ORGANIZER:MAILTO:jane_doe@host1.com ATTENDEE:MAILTO:john_public@host2.com DTSTAMP:19970901T100000Z FREEBUSY;VALUE=PERIOD:19971015T050000Z/PT8H30M, 19971015T160000Z/PT5H30M,19971015T223000Z/PT6H30M URL:http://host2.com/pub/busy/jpublic-01.ifb COMMENT:This iCalendar file contains busy time information for the next three months. END:VFREEBUSY Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.1-event-1.ics0000644000175000017500000000032512101464332023720 0ustar richardcrichardcBEGIN:VEVENT UID:19970901T130000Z-123401@host.com DTSTAMP:19970901T1300Z DTSTART:19970903T163000Z DTEND:19970903T190000Z SUMMARY:Annual Employee Review CLASS:PRIVATE CATEGORIES:BUSINESS,HUMAN RESOURCES END:VEVENT Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.2-todo-1.ics0000644000175000017500000000036012101464332023544 0ustar richardcrichardcBEGIN:VTODO UID:19970901T130000Z-123404@host.com DTSTAMP:19970901T1300Z DTSTART:19970415T133000Z DUE:19970416T045959Z SUMMARY:1996 Income Tax Preparation CLASS:CONFIDENTIAL CATEGORIES:FAMILY,FINANCE PRIORITY:1 STATUS:NEEDS-ACTION END:VTODO Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.6-alarm-1.ics0000644000175000017500000000024712101464332023703 0ustar richardcrichardcBEGIN:VALARM TRIGGER;VALUE=DATE-TIME:19970317T133000Z REPEAT:4 DURATION:PT15M ACTION:AUDIO ATTACH;FMTTYPE=audio/basic:ftp://host.com/pub/sounds/bell-01.aud END:VALARM Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.1-event-3.ics0000644000175000017500000000033412101464332023722 0ustar richardcrichardcBEGIN:VEVENT UID:19970901T130000Z-123403@host.com DTSTAMP:19970901T1300Z DTSTART:19971102 SUMMARY:Our Blissful Anniversary CLASS:CONFIDENTIAL CATEGORIES:ANNIVERSARY,PERSONAL,SPECIAL OCCASION RRULE:FREQ=YEARLY END:VEVENT Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.5-timezone-1.ics0000644000175000017500000000047712101464332024445 0ustar richardcrichardcBEGIN:VTIMEZONE TZID:US-Eastern LAST-MODIFIED:19870101T000000Z BEGIN:STANDARD DTSTART:19971026T020000 RDATE:19971026T020000 TZOFFSETFROM:-0400 TZOFFSETTO:-0500 TZNAME:EST END:STANDARD BEGIN:DAYLIGHT DTSTART:19971026T020000 RDATE:19970406T020000 TZOFFSETFROM:-0500 TZOFFSETTO:-0400 TZNAME:EDT END:DAYLIGHT END:VTIMEZONE Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.6-alarm-2.ics0000644000175000017500000000022312101464332023676 0ustar richardcrichardcBEGIN:VALARM TRIGGER:-PT30M REPEAT:2 DURATION:PT15M ACTION:DISPLAY DESCRIPTION:Breakfast meeting with executive\n team at 8:30 AM EST. END:VALARM Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.3-journal-1.ics0000644000175000017500000000115312101464332024253 0ustar richardcrichardcBEGIN:VJOURNAL UID:19970901T130000Z-123405@host.com DTSTAMP:19970901T1300Z DTSTART;VALUE=DATE:19970317 SUMMARY:Staff meeting minutes DESCRIPTION:1. Staff meeting: Participants include Joe\, Lisa and Bob. Aurora project plans were reviewed. There is currently no budget reserves for this project. Lisa will escalate to management. Next meeting on Tuesday.\n 2. Telephone Conference: ABC Corp. sales representative called to discuss new printer. Promised to get us a demo by Friday.\n 3. Henry Miller (Handsoff Insurance): Car was totaled by tree. Is looking into a loaner car. 654-2323 (tel). END:VJOURNAL Text-vFile-asData-0.08/examples/rfc2445-objects/README0000644000175000017500000000033112101464332022152 0ustar richardcrichardcA selection of sample calendars for testing. Filenames take the form x.y.z-type-n.ics Where "x.y.z" is the section from RFC2445 that the example is from, "type" is the object type, and "n" is the example number. Text-vFile-asData-0.08/examples/rfc2445-objects/4.4-calendar-1.ics0000644000175000017500000000027012101464332024206 0ustar richardcrichardcBEGIN:VCALENDAR VERSION:2.0 PRODID:-//hacksw/handcal//NONSGML v1.0//EN BEGIN:VEVENT DTSTART:19970714T170000Z DTEND:19970715T035959Z SUMMARY:Bastille Day Party END:VEVENT END:VCALENDAR Text-vFile-asData-0.08/examples/rfc2445-objects/4.6.4-freebusy-3.ics0000644000175000017500000000043612101464332024433 0ustar richardcrichardcBEGIN:VFREEBUSY ORGANIZER:jsmith@host.com DTSTART:19980313T141711Z DTEND:19980410T141711Z FREEBUSY:19980314T233000Z/19980315T003000Z FREEBUSY:19980316T153000Z/19980316T163000Z FREEBUSY:19980318T030000Z/19980318T040000Z URL:http://www.host.com/calendar/busytime/jsmith.ifb END:VFREEBUSY Text-vFile-asData-0.08/Makefile.PL0000644000175000017500000000060212101467715016717 0ustar richardcrichardcuse strict; use ExtUtils::MakeMaker; WriteMakefile( NAME => 'Text::vFile::asData', AUTHOR => 'Richard Clamp ', LICENSE => 'perl', VERSION_FROM => 'lib/Text/vFile/asData.pm', ABSTRACT_FROM => 'lib/Text/vFile/asData.pm', PREREQ_PM => { 'Test::More' => '0.88', 'Class::Accessor::Chained' => 0 } ); Text-vFile-asData-0.08/MANIFEST0000644000175000017500000000243312101467715016102 0ustar richardcrichardcChanges META.yml META.json Makefile.PL MANIFEST MANIFEST.SKIP bin/rota_ical.cgi bin/holidays_ical bin/v2yaml bin/wgo examples/Text-vCard/README examples/Text-vCard/evolution.vcf examples/Text-vCard/full_card_v2_1.vcf examples/Text-vCard/full_card_v3.vcf examples/Text-vCard/phone_v1.vcf examples/Text-vCard/simple.vcf examples/Text-vFile/02_simple.dat examples/Text-vFile/03_multi.dat examples/Text-vFile/README examples/rfc2445-objects/4.4-calendar-1.ics examples/rfc2445-objects/4.6.1-event-1.ics examples/rfc2445-objects/4.6.1-event-2.ics examples/rfc2445-objects/4.6.1-event-3.ics examples/rfc2445-objects/4.6.2-todo-1.ics examples/rfc2445-objects/4.6.3-journal-1.ics examples/rfc2445-objects/4.6.4-freebusy-1.ics examples/rfc2445-objects/4.6.4-freebusy-2.ics examples/rfc2445-objects/4.6.4-freebusy-3.ics examples/rfc2445-objects/4.6.5-timezone-1.ics examples/rfc2445-objects/4.6.5-timezone-2.ics examples/rfc2445-objects/4.6.5-timezone-3.ics examples/rfc2445-objects/4.6.5-timezone-4.ics examples/rfc2445-objects/4.6.6-alarm-1.ics examples/rfc2445-objects/4.6.6-alarm-2.ics examples/rfc2445-objects/4.6.6-alarm-3.ics examples/rfc2445-objects/4.6.6-alarm-4.ics examples/rfc2445-objects/README lib/Text/vFile/asData.pm t/01vfile.t t/02examples.t t/03usage.t t/pod.t t/parse_line.t t/user_with_image.vcf Text-vFile-asData-0.08/lib/0000755000175000017500000000000012101467724015515 5ustar richardcrichardcText-vFile-asData-0.08/lib/Text/0000755000175000017500000000000012101467724016441 5ustar richardcrichardcText-vFile-asData-0.08/lib/Text/vFile/0000755000175000017500000000000012101467724017506 5ustar richardcrichardcText-vFile-asData-0.08/lib/Text/vFile/asData.pm0000644000175000017500000002106612101467715021246 0ustar richardcrichardcpackage Text::vFile::asData; use strict; use warnings; no warnings 'uninitialized'; use base qw( Class::Accessor::Chained::Fast ); __PACKAGE__->mk_accessors(qw( preserve_params )); our $VERSION = '0.08'; =head1 NAME Text::vFile::asData - parse vFile formatted files into data structures =head1 SYNOPSIS use Text::vFile::asData; open my $fh, "foo.ics" or die "couldn't open ics: $!"; my $data = Text::vFile::asData->new->parse( $fh ); =head1 DESCRIPTION Text::vFile::asData reads vFile format files, such as vCard (RFC 2426) and vCalendar (RFC 2445). =cut sub _unwrap_lines { my $self = shift; my @lines; for (@_) { my $line = $_; # $_ may be readonly $line =~ s{[\r\n]+$}{}; # lines SHOULD end CRLF if ($line =~ /^[ \t](.*)/) { # Continuation line (RFC Sect. 4.1) die "Continuation line, but no preceding line" unless @lines; $lines[-1] .= $1; next; } push @lines, $line; } return @lines; } sub parse { my $self = shift; my $fh = shift; return $self->parse_lines( <$fh> ); } # like Text::ParseWords' parse_line, only C-style so the regex engine doesn't # blow its stack, and it's also got a $limit like split # this only took a trainride, so I'm pretty sure there are lurking # corner cases - when I get a tuit I'll take the Text::ParseWords # tests and run them through it sub parse_line { my ($delim, $keep, $text, $limit) = @_; my ($current, @parts); my ($quote, $escaped); while (length $text) { if ($text =~ s{^(\\)}{}) { $current .= $1 if $escaped || $keep; $escaped = !$escaped; next; } if (!$quote && !$escaped && $text =~ s{^$delim}{}) { push @parts, $current; $current = undef; if (defined $limit && @parts == $limit -1) { return @parts, $text; } } else { # pull the character off to take a looksee $text =~ s{(.)}{}; my $char = $1; if ($char eq '"' && !$escaped) { # either it's defined and matches, in which case we # clear the quote variable, or it's undefined which # makes this quote an opening quote $quote = !$quote; $current .= $char if $keep; } else { $current .= $char; } } $escaped = 0; } return @parts, $current; } sub parse_lines { my $self = shift; my @path; my $current; for ($self->_unwrap_lines( @_ )) { # Ignore leading or trailing blank lines at the top/bottom of the # input. Not sure about completely blank lines within the input next if scalar @path == 0 and $_ =~ /^\s*$/; if (/^BEGIN:(.*)/i) { push @path, $current; $current = { type => $1 }; push @{ $path[-1]{objects} }, $current; next; } if (/^END:(.*)/i) { die "END $1 in $current->{type}" unless lc $current->{type} eq lc $1; $current = pop @path; next; } # we'd use Text::ParseWords here, but it likes to segfault. my ($name, $value) = parse_line( ':', 1, $_, 2); $value = '' unless defined $value; my @params = parse_line( ';', 0, $name ); $name = shift @params; $value = { value => $value }; foreach my $param (@params) { my ($p_name, $p_value) = split /=/, $param; push @{ $value->{params} }, { $p_name => $p_value } if $self->preserve_params; $value->{param}{ $p_name } = $p_value; } push @{ $current->{properties}{ $name } }, $value; } # something did a BEGIN but no END - TODO, unwind this nicely as # it may be more than one level die "BEGIN $current->{type} without matching END" if @path; return $current; } # this might not strictly comply sub generate_lines { my $self = shift; my $this = shift; my @lines; # XXX all the existence checks are to prevent auto-vivification # breaking if_diff tests - do we mind, or should the fields have been # there anyway? push @lines, "BEGIN:$this->{type}" if exists $this->{type}; if (exists $this->{properties}) { while (my ($name, $v) = each %{ $this->{properties} } ) { for my $value (@$v) { # XXX so we're taking params in preference to param, # let's be sure to document that when we document this # method my $param = join ';', '', map { my $hash = $_; map { "$_" . (defined $hash->{$_} ? "=" . $hash->{$_} : "") } keys %$hash } @{ $value->{params} || [ $value->{param} ] }; my $line = "$name$param:$value->{value}"; # wrapping, but done ugly my @chunks = $line =~ m/(.{1,72})/g; push @lines, shift @chunks; push @lines, map { " $_" } @chunks; } } } if (exists $this->{objects}) { push @lines, $self->generate_lines( $_ ) for @{ $this->{objects} } } push @lines, "END:$this->{type}" if exists $this->{type}; return @lines; } 1; __END__ =head1 DATA STRUCTURE A vFile contains one or more objects, delimited by BEGIN and END tags. BEGIN:VCARD ... END:VCARD Objects may contain sub-objects; BEGIN:VCALENDAR ... BEGIN:VEVENT ... END:VEVENT ... ENV:VCALENDAR Each object consists of one or more properties. Each property consists of a name, zero or more optional parameters, and then a value. This fragment: DTSTART;VALUE=DATE:19970317 identifies a property with the name, C, the parameter C, which has the value C, and the property's value is C<19970317>. Those of you with an XML bent might find this more recognisable as: 19970317 The return value from the C method is a hash ref. The top level key, C, refers to an array ref. Each entry in the array ref is a hash ref with two or three keys. The value of the first key, C, is a string corresponding to the type of the object. E.g., C, C, and so on. The value of the second key, C, is a hash ref, with property names as keys, and an array ref of those property values. It's an array ref, because some properties may appear within an object multiple times with different values. For example; BEGIN:VEVENT ATTENDEE;CN="Nik Clayton":mailto:nik@FreeBSD.org ATTENDEE;CN="Richard Clamp":mailto:richardc@unixbeard.net ... END:VEVENT Each entry in the array ref is a hash ref with one or two keys. The first key, C, corresponds to the property's value. The second key, C, contains a hash ref of the property's parameters. Keys in this hash ref are the parameter's name, the value is the parameter's value. (If you enable the C option there is an additional key populated, called C. It is an array ref of hash refs, each hash ref is the parameter's name and the parameter's value - these are collected in the order they are encountered to prevent hash collisions as seen in some vCard files) line.) The third key in the top level C hash ref is C. If it exists, it indicates that sub-objects were found. The value of this key is an array ref of sub-objects, with identical keys and behaviour to that of the top level C key. This recursive structure continues, nesting as deeply as there were sub-objects in the input file. The C script that comes with this distribution displays the format of a vFile as YAML. C has examples of picking out the relevant information from the data structure. =head1 AUTHORS Richard Clamp and Nik Clayton =head1 COPYRIGHT Copyright 2004, 2010, 2013 Richard Clamp and Nik Clayton. All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 CAVEATS We don't do any decoding of property values, including descaping C<\,>, we're still undecided as to whether this is a bug. =head1 BUGS Aside from the TODO list items, none known. =head1 SEE ALSO Text::vFile - parses to objects, doesn't handle nested items RFC 2426 - vCard specification RFC 2445 - vCalendar specification =cut # Emacs local variables to keep the style consistent Local Variables: cperl-indent-level: 4 End: Text-vFile-asData-0.08/bin/0000755000175000017500000000000012101467724015517 5ustar richardcrichardcText-vFile-asData-0.08/bin/rota_ical.cgi0000755000175000017500000000630612101464332020140 0ustar richardcrichardc#!/usr/bin/perl use strict; use warnings; use Text::vFile::asData; use Digest::MD5 qw(md5_hex); use DateTime; use CGI; my $file = -e 'SystemsSupportRota' ? 'SystemsSupportRota' : 'http://intranet.fotango.private/index.php?title=Systems_Support_Rota&action=raw'; =head1 NAME rota_ical.cgi - scrape the SystemsSupportRota wiki page into ics =head1 DESCRIPTION =cut my @tasks; my %rrule; sub make_events { my $when = shift; my %who; @who{ @tasks } = @_; my $year = DateTime->now->year; return unless $when =~ m{(\S+)\s+(\d+)\s*/\s*(\d+)}; my ($weekday, $day, $month) = ($1, $2, $3); my $start = DateTime->new( year => $year, month => $month, day => $day ); my $end = $start->clone->add( days => 1 ); my $is_rrule; if ($when =~ /From/) { # establish an rrule for that weekday push @{ $rrule{$weekday} }, { start => $start->epoch, map { $_ => md5_hex( "$when $who{$_} $_" ) } @tasks, }; $is_rrule = 1; } # find the latest rrule that covers this date my ($rrule) = grep { $start->epoch >= $_->{start} } sort { $a->{start} <=> $b->{start} } @{ $rrule{ $weekday } || [] }; return map +{ type => 'VEVENT', properties => { SUMMARY => [ { value => "$who{$_} $_" } ], DESCRIPTION => [ { value => "$when $who{$_} $_" } ], DTSTART => [ { value => $start->ymd(''), param => { VALUE => 'DATE' }, } ], DTEND => [ { value => $end->ymd(''), param => { VALUE => 'DATE' }, } ], UID => [ { value => $rrule ? $rrule->{ $_ } : md5_hex( "$when $who{$_} $_" ) } ], ($is_rrule ? ( RRULE => [ { value => "FREQ=WEEKLY;INTERVAL=1" } ] ) : $rrule ? ( 'RECURRENCE-ID' => [ { param => { VALUE => "DATE" }, value => $start->ymd('') } ] ) : ()), }, }, sort grep { $who{$_} } @tasks; } my $cal = { type => 'VCALENDAR', properties => { 'X-WR-CALNAME' => [ { value => "Systems Rota" } ], }, objects => [], }; # sometimes, we want to use a url so wrap read_file as get_lines sub get_lines { my $file = shift; if ($file =~ m{^https?://}) { # s'really a url require LWP::Simple; my $content = LWP::Simple::get( $file ); return split $/, $content; } require File::Slurp; return File::Slurp::read_file( $file ); } sub parse_tables { my (@rows, @row, $in_table); for (@_) { chomp; /^{\|/ and do { $in_table = 1; next }; /^\|}/ and do { $in_table = 0; next }; next unless $in_table; /^\|-/ and do { push @rows, [@row] if @row; @row = (); next; }; /^\| (.*)/ and do { push @row, $1; next; }; print "Didn't expect: $_\n"; } return @rows, (@row ? [@row] : ()); } for (parse_tables( get_lines( $file ) )) { $_->[0] =~ /Date/ and do { (undef, @tasks) = @$_; next; }; push @{ $cal->{objects} }, make_events( @$_ ); } print CGI->header('text/calendar'); print map "$_\n", Text::vFile::asData->generate_lines( $cal ); Text-vFile-asData-0.08/bin/v2yaml0000644000175000017500000000031112101464332016637 0ustar richardcrichardc#!/usr/bin/perl use strict; use warnings; use lib qw(lib); use IO::File; use Text::vFile::asData; use YAML; foreach(@ARGV) { print Dump( Text::vFile::asData->new->parse( IO::File->new( $_ ) ) ) } Text-vFile-asData-0.08/bin/holidays_ical0000755000175000017500000000661712101464332020253 0ustar richardcrichardc#!/usr/bin/perl use strict; use warnings; use Text::vFile::asData; use Digest::MD5 qw(md5_hex); use DateTime; use CGI; my $file = -e 'Holidays' ? 'Holidays' : 'http://intranet.fotango.private/index.php?title=Holidays&action=raw'; =head1 NAME holidays_ical - scrape the Holidays wiki page into ics =head1 DESCRIPTION So this is why I wanted an iCal generator/parser. We have an intranet, with a page for who's going to be out of the office which blech suggested might be good to have available as .ics. The page is structured roughly like so: = 2004 = == February == * [[Richard Clamp]] ** 1st - 3rd Baying at the moon This script scrapes that page and makes it available as a vCalendar. It's called as a cgi so you can subscribe to it with iCal.app and phpICal. =head1 AUTHOR Richard Clamp =cut # sometimes, we want to use a url so wrap read_file as get_lines sub get_lines { my $file = shift; if ($file =~ m{^https?://}) { # s'really a url require LWP::Simple; my $content = LWP::Simple::get( $file ); return split $/, $content; } require File::Slurp; return File::Slurp::read_file( $file ); } # horrible stateful stuff, but easier than driving Template::Extract my ($year, $month, $who); my %months = ( January => 1, February => 2, March => 3, April => 4, May => 5, June => 6, July => 7, August => 8, September => 9, October => 10, November => 11, December => 12 ); sub guesstimate_event { my $event = shift; my $when = $event; my ($firstday, $lastday); if ($when =~ /(\d+)(?:st|nd|rd|th)?\s*(?:to|-)\s*(\d+)/i) { #print "From $1 to $2: $event\n"; ($firstday, $lastday) = ($1, $2); } elsif ($when =~ /(\d+)/) { ($firstday, $lastday) = ($1, $1); } else { warn "didn't handle $event"; return; } my $start = DateTime->new( year => $year, month => $months{ $month }, day => $firstday, ); my $end = DateTime->new( year => $year, month => $months{ $month }, day => $lastday )->add( days => 1, ( $firstday > $lastday ? ( months => 1 ) : () ) # 28th - 2nd probably means it went over a month ); return { type => 'VEVENT', properties => { SUMMARY => [ { value => $who } ], DESCRIPTION => [ { value => $event } ], DTSTART => [ { value => $start->ymd(''), param => { VALUE => 'DATE' }, } ], DTEND => [ { value => $end->ymd(''), param => { VALUE => 'DATE' }, } ], UID => [ { value => md5_hex( "$year $month $who - $event" ), } ], }, }; } my $cal = { type => 'VCALENDAR', properties => { 'X-WR-CALNAME' => [ { value => "Fotango Holidays" } ], }, objects => [], }; for (get_lines( $file )) { next if /^\s*$/; /^= (.*) =/ and do { $year = $1; next }; /^== (.*) ==/ and do { $month = $1; next }; /^\* \[\[(.*)\]\]/ and do { $who = $1; next }; /^\*\* (.*)/ and do { #print "year = $year, month = $month, event = $1\n"; push @{ $cal->{objects} }, guesstimate_event( $1 ); next; }; # warn "unhandled line: $_"; } print CGI->header('text/calendar'); print map "$_\n", Text::vFile::asData->generate_lines( $cal ); Text-vFile-asData-0.08/bin/wgo0000755000175000017500000002052012101464332016230 0ustar richardcrichardc#!/usr/bin/perl -w # # What's Going On. Given one or more .ics files on the command line, # produces a text report showing what's happening in the next six weeks. # # This was my main reason for working on this -- I've been producing things # like this by hand for a mailing list of friends on and off for the past # six years, and was too lazy to automate the damn thing. # # To see it in action, try fetching the london.pm calendar from # http://london.pm.org/ical.ics, then run "perl wgo ical.ics" # # Nik Clayton, use strict; use lib '../lib'; use Text::vFile::asData; use DateTime; use DateTime::Span; use DateTime::Format::ICal; use IO::File; # Could use Lingua::*::Inflect, but it's overkill for a quick demo # 1 2 3 4 5 6 7 8 9 10 my @inflect = qw(st nd rd th th th th th th th th th th th th th th th th th st nd rd th th th th th th th st); # Get the current time, and the time six weeks from now. Then build a # DateTime::Span. We'll test every event we find to see if it, or any of # it's recurrences, are inside this span. If they are, we need to include # them in the output. # # Yes, start time and end time should be parameters to the script. my $start_dt = DateTime->now(); my $end_dt = $start_dt + DateTime::Duration->new(weeks => 6); my $span = DateTime::Span->from_datetimes(start => $start_dt, end => $end_dt); my @cals = (); # List of refs returned by parse() my %events = (); # Events we're interested in. Key is # date/time formatted as an ICal string, # value is a list of events happening at # that time. foreach(@ARGV) { push @cals, Text::vFile::asData->new->parse(IO::File->new($_)); } foreach my $cal (@cals) { foreach my $obj (@{ $cal->{objects}->[0]->{objects} }) { next if $obj->{type} ne 'VEVENT'; # Not interested in non events my %e = (); # Info about this event my $p = $obj->{properties}; # The event's properties next if ! defined $p->{SUMMARY}->[0]->{value}; $e{start} = DateTime::Format::ICal->parse_datetime($p->{DTSTART}->[0]->{value}); if(defined $p->{DTEND}->[0]->{value}) { $e{end} = DateTime::Format::ICal->parse_datetime($p->{DTEND}->[0]->{value}); # iCal represents all-day events by using ;VALUE=DATE and setting # DTEND=end_date + 1 $e{end}->subtract( days => 1 ) if $p->{DTEND}[0]{param}{VALUE} && $p->{DTEND}[0]{param}{VALUE} eq 'DATE' } else { $e{duration} = DateTime::Format::ICal->parse_duration($p->{DURATION}[0]{value} || "PT1S" ); $e{end} = $e{start} + $e{duration}; } $e{span} = DateTime::Span->from_datetimes(start => $e{start}, end => $e{end}); $e{summary} = $p->{SUMMARY}->[0]->{value}; $e{desc} = $p->{DESCRIPTION}->[0]->{value}; $e{desc} ||= ''; $e{summary} =~ s/\\(.)/$1/g; # Backslash escape removal $e{desc} =~ s/\\(.)/$1/g; # Handle event recurrences. If there's a recurrence rule (RRULE), then # use that. if(exists $p->{RRULE}) { # $e{recur} = DateTime::Set $e{recur} = DateTime::Format::ICal->parse_recurrence(recurrence => $p->{RRULE}->[0]->{value}, dtstart => $e{start}); } else { # If the event is a multi-day event then synthesise copies of the # event for every day on which it occurs. # # Why? Suppose you're looking at a 5 day span, and you have an # event that starts on day 2 and finishes on day 4 (3 days in total). # The ->iterator() considers that this is one occurence of the event, # rather than 3. So create recurrences so the iterator behaves in a # more useful fashion. $e{recur} = DateTime::Set->from_recurrence( recurrence => sub { $_[0]->truncate(to => 'day')->add(days => 1); }, span => $e{span}); $e{recur} = $e{recur}->union(DateTime::Set->from_datetimes(dates => [$e{start}])); } # Synthesise a flag that indicates that this is an all-day event. Not # sure if this is the correct way of detecting this, but it works so # far... $e{allday} = exists $p->{DTSTART}->[0]->{param}->{VALUE} and $p->{DTSTART}->[0]->{param}->{VALUE} eq 'DATE' ? 1 : 0; # Check to see if it's in the time span we're interested in if($e{recur}->intersects($span)) { my $int_set = $e{recur}->intersection($span); # Change the event's recurrence details so that only the events # inside the time span we're interested in are listed. $e{recur} = $int_set; my $iter = $int_set->iterator(); while(my $dt = $iter->next()) { $e{dt} = $dt; # Save a copy of the event (es = event saved), and store it in # the list of event refs keyed off the ICal date my %es = %e; push @{$events{ $dt->ymd() }}, \%es; } } } } my $e; # Hash ref of event info my $last_ed = ''; # Last event date we processed foreach my $ed (sort keys %events) { # $ed = event date ('yyyy-mm-dd') foreach $e (sort by_type_time @{$events{$ed}}) { # Build the first part of the output line. For the first event of the # day include the date, month, and day abbreviation. For subsequent # events on the same day this is the empty string. This makes for # nicer output, as it's more obvious which events share a day. if($ed ne $last_ed) { # First event of the day $e->{startstring} = sprintf("%2d %s (%s)", $e->{dt}->day(), $e->{dt}->month_abbr(), $e->{dt}->day_abbr()); } else { # Second and subsequent events $e->{startstring} = ''; } $last_ed = $ed; # If it's not an all day event then the first part of the summary is # the time the event occurs $e->{summary} = sprintf("%02d:%02d - %02d:%02d, %s", $e->{span}->start()->hour(), $e->{span}->start()->minute(), $e->{span}->end()->hour(), $e->{span}->end()->minute(), $e->{summary}) unless $e->{allday}; # If this is the second or subsequent appearance of a multi-day event, # replace the description (if it exists) with a pointer to the first # occurence of the description if($e->{recur}->min()->ymd() ne $ed and $e->{desc} ne '') { $e->{desc} = sprintf("See %d%s %s entry for details.", $e->{recur}->min()->day(), $inflect[$e->{recur}->min()->day() - 1], $e->{recur}->min()->month_abbr()); } $e->{summary} = punctuate($e->{summary}) . ' ' . punctuate($e->{desc}) if $e->{desc} ne ''; write; } } exit; sub by_type_time { # For sorting lists of events # Two events on the same day? All day events come first return -1 if $a->{allday} and ! $b->{allday}; return 1 if $b->{allday} and ! $a->{allday}; # If they're both all day events, sort by summary text return $a->{summary} cmp $b->{summary} if $a->{allday} and $b->{allday}; # Otherwise, sort by start time return $a->{dt} <=> $b->{dt}; } # Try and make sure a string ends with sensible punctuation sub punctuate { my $str = shift; return '' if ! defined $str; $str =~ s/\s*$//g; $str .= '.' unless $str =~ /[\.\?!]$/; return $str; } format STDOUT = @<<<<<<<<<<< | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $e->{startstring}, $e->{summary} ~ | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $e->{summary} ~ | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $e->{summary} ~ | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $e->{summary} ~ | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $e->{summary} ~ | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $e->{summary} ~ | ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $e->{summary} | . Text-vFile-asData-0.08/META.yml0000664000175000017500000000105212101467724016220 0ustar richardcrichardc--- abstract: 'parse vFile formatted files into data structures' author: - 'Richard Clamp ' build_requires: ExtUtils::MakeMaker: 0 configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 6.6302, CPAN::Meta::Converter version 2.120630' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4 name: Text-vFile-asData no_index: directory: - t - inc requires: Class::Accessor::Chained: 0 Test::More: 0.88 version: 0.08