|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Text::VCardFast;  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
3
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
84377
 | 
 use strict;  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
115
 | 
    | 
| 
4
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
14
 | 
 use warnings;  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
115
 | 
    | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
6
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
1908
 | 
 use Encode qw(decode_utf8 encode_utf8);  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29610
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
327
 | 
    | 
| 
7
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
1900
 | 
 use MIME::Base64 qw(decode_base64 encode_base64);  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2388
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9327
 | 
    | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 require Exporter;  | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our @ISA = qw(Exporter);  | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Items to export into callers namespace by default. Note: do not export  | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # names by default without a very good reason. Use EXPORT_OK instead.  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Do not simply export all your public functions/methods/constants.  | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # This allows declaration	use Text::VCardFast ':all';  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # will save memory.  | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our %EXPORT_TAGS = ( 'all' => [ qw(  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	vcard2hash  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	hash2vcard  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ) ] );  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our @EXPORT = qw(  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	vcard2hash  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	hash2vcard  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 );  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = '0.08';  | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 require XSLoader;  | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 XSLoader::load('Text::VCardFast', $VERSION);  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # public API  | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
39
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
  
1
  
 | 
1854
 | 
 sub vcard2hash { &vcard2hash_c }  | 
| 
40
 | 
15
 | 
 
 | 
 
 | 
  
15
  
 | 
  
1
  
 | 
109383
 | 
 sub hash2vcard { &hash2vcard_pp }  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Implementation  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub vcard2hash_c {  | 
| 
45
 | 
31
 | 
 
 | 
 
 | 
  
31
  
 | 
  
0
  
 | 
2975
 | 
     my $vcard = shift;  | 
| 
46
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
60
 | 
     my %params = @_;  | 
| 
47
 | 
31
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
74
 | 
     if (utf8::is_utf8($vcard)) {  | 
| 
48
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
         utf8::encode($vcard);  | 
| 
49
 | 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
         $params{is_utf8} = 1;  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
51
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1236
 | 
     my $hash = Text::VCardFast::_vcard2hash($vcard, \%params);  | 
| 
52
 | 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
63
 | 
     return $hash;  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # pureperl version  | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # VCard parsing and formatting {{{  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %RFC6868Map = ("n" => "\n", "^" => "^", "'" => "\"");  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %RFC6868RevMap = reverse %RFC6868Map;  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %UnescapeMap = ("n" => "\n", "N" => "\n");  | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $Pos = 1;  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my @PropOutputOrder = qw(version fn n nickname lang gender org title role bday anniversary email tel adr url impp);  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %PropOutputOrder = map { $_ => $Pos++ } @PropOutputOrder;  | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my @ParamOutputOrder = qw(type pref);  | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my %ParamOutputOrder = map { $_ => $Pos++ } @ParamOutputOrder;  | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub vcard2hash_pp {  | 
| 
70
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
  
0
  
 | 
52626
 | 
   my $vcard = shift;  | 
| 
71
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
   my %params = @_;  | 
| 
72
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
221
 | 
   return vcardlines2hash_pp(\%params, (split /\r?\n/, $vcard));  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub vcardlines2hash_pp {  | 
| 
76
 | 
12
 | 
 
 | 
 
 | 
  
12
  
 | 
  
0
  
 | 
12
 | 
   my $args = shift;  | 
| 
77
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
   local $_;  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
79
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
   my %MultiFieldMap;  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my %MultiParamMap;  | 
| 
81
 | 
12
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
31
 | 
   if ($args->{multival}) {  | 
| 
82
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     %MultiFieldMap = map { $_ => 1 } @{$args->{multival}};  | 
| 
 
 | 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
    | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
84
 | 
12
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
27
 | 
   if ($args->{multiparam}) {  | 
| 
85
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
     %MultiParamMap = map { $_ => 1 } @{$args->{multiparam}};  | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
    | 
| 
 
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
    | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # rfc2425, rfc2426, rfc6350, rfc6868  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
90
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
   my @Path;  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $Current;  | 
| 
92
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
   while ($_ = shift @_) {  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Strip EOL  | 
| 
94
 | 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
223
 | 
     s/\r?\n$//;  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # 5.8.1 - Unfold lines if next line starts with space or tab  | 
| 
97
 | 
190
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
680
 | 
     if (@_ && $_[0] =~ s/^[ \t]//) {  | 
| 
98
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
       $_ .= shift @_;  | 
| 
99
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
       redo;  | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Ignore empty lines  | 
| 
103
 | 
169
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
314
 | 
     next if /^\s*$/;  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
105
 | 
169
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
257
 | 
     if (/^BEGIN:(.*)/i) {  | 
| 
106
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
       push @Path, $Current;  | 
| 
107
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
49
 | 
       $Current = { type => lc $1 };  | 
| 
108
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
       push @{ $Path[-1]{objects} }, $Current;  | 
| 
 
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
    | 
| 
109
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
       next;  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
111
 | 
156
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
253
 | 
     if (/^END:(.*)/i) {  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       die "END $1 in $Current->{type}"  | 
| 
113
 | 
13
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
34
 | 
         unless $Current->{type} eq lc $1;  | 
| 
114
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
       $Current = pop @Path;  | 
| 
115
 | 
13
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
22
 | 
       return $Current if ($args->{only_one} and not @Path);  | 
| 
116
 | 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
       next;  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # 5.8.2 - Parse '[group "."] name *(";" param) ":" value'  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #  In v2.1, params may not have "=value" part  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #  In v4, "," is allowed in non-quoted param value  | 
| 
122
 | 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
324
 | 
     my ($Name) = /^([^;:]*)/gc;  | 
| 
123
 | 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
370
 | 
     my @Params = /\G;(?:([\w\-]+)=)?("[^"]*"|[^";:=]*)/gc;  | 
| 
124
 | 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
252
 | 
     my ($Value) = /\G:(.*)$/g;  | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # 5.8.2 - Type names and parameter names are case insensitive  | 
| 
127
 | 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
157
 | 
     my $LName = lc $Name;  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
129
 | 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
98
 | 
     my %Props;  | 
| 
130
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Remove group from each property name and add as attribute  | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #  (in v4, group names are case insensitive as well)  | 
| 
133
 | 
143
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
261
 | 
     if ($LName =~ s/^(.+)\.(.*?)$/$2/) {  | 
| 
134
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
       $Props{group} = $1;  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
137
 | 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
183
 | 
     $Props{name} = $LName;  | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Parse out parameters  | 
| 
140
 | 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
100
 | 
     my %Params;  | 
| 
141
 | 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
182
 | 
     while (@Params) {  | 
| 
142
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # Parsed into param => param-value pairs  | 
| 
143
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
121
 | 
       my ($PName, $PValue) = splice @Params, 0, 2;  | 
| 
144
 | 
100
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
137
 | 
       if (not defined $PName) {  | 
| 
145
 | 
7
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10
 | 
         if ($args->{barekeys}) {  | 
| 
146
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
           $PName = $PValue;  | 
| 
147
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
           $PValue = undef;  | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         else {  | 
| 
150
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7
 | 
           $PName = 'type';  | 
| 
151
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
152
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # 5.8.2 - parameter names are case insensitive  | 
| 
155
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
85
 | 
       my $LPName = lc $PName;  | 
| 
156
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
157
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
91
 | 
       my @PValue = (undef);  | 
| 
158
 | 
100
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
128
 | 
       if (defined $PValue) {  | 
| 
159
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
127
 | 
         $PValue =~ s/^"(.*)"$/$1/;  | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # \n needed for label, but assume any \; is meant to be ; as well  | 
| 
161
 | 
100
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
93
 | 
         $PValue =~ s#\\(.)#$UnescapeMap{$1} // $1#ge;  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
    | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # And RFC6868 recoding  | 
| 
163
 | 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
78
 | 
         $PValue =~ s/\^([n^'])/$RFC6868Map{$1}/g;  | 
| 
164
 | 
100
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
135
 | 
         if ($MultiParamMap{$LPName}) {  | 
| 
165
 | 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
115
 | 
           @PValue = split /,/, $PValue;  | 
| 
166
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         else {  | 
| 
168
 | 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
           @PValue = ($PValue);  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
172
 | 
100
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
110
 | 
       if (exists $Params{$LPName}) {  | 
| 
173
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10
 | 
         push @{$Params{$LPName}}, @PValue;  | 
| 
 
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
    | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       } else {  | 
| 
175
 | 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
198
 | 
         $Params{$LPName} = \@PValue;  | 
| 
176
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
177
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
178
 | 
143
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
235
 | 
     $Props{params} = \%Params if keys %Params;  | 
| 
179
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
180
 | 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
117
 | 
     my $Encoding = $Params{encoding};  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
182
 | 
143
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
404
 | 
     if ($MultiFieldMap{$LName}) {  | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # use negative 'limit' to force trailing fields  | 
| 
184
 | 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
148
 | 
       $Value = [ split /(?
 | 
| 
185
 | 
26
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
88
 | 
       s#\\(.)#$UnescapeMap{$1} // $1#ge for @$Value;  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
186
 | 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
       $Props{values} = $Value;  | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif ($Encoding && lc $Encoding eq 'b') {  | 
| 
188
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # Don't bother unescaping base64 value  | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
190
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $Props{value} = $Value;  | 
| 
191
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
192
 | 
117
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
129
 | 
       $Value =~ s#\\(.)#$UnescapeMap{$1} // $1#ge;  | 
| 
 
 | 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
66
 | 
    | 
| 
193
 | 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
113
 | 
       $Props{value} = $Value;  | 
| 
194
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
196
 | 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
98
 | 
     push @{$Current->{properties}->{$LName}}, \%Props;  | 
| 
 
 | 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
580
 | 
    | 
| 
197
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
198
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # something did a BEGIN but no END - TODO, unwind this nicely as  | 
| 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # it may be more than one level  | 
| 
201
 | 
12
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
28
 | 
   die "BEGIN $Current->{type} without matching END"  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     if @Path;  | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
204
 | 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
45
 | 
   return $Current;  | 
| 
205
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
207
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub hash2vcard_pp {  | 
| 
208
 | 
15
 | 
 
 | 
  
 50
  
 | 
  
15
  
 | 
  
0
  
 | 
29
 | 
   return join "", map { $_ . ($_[1] // "\n") } hash2vcardlines_pp($_[0]);  | 
| 
 
 | 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
563
 | 
    | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub hash2vcardlines_pp {  | 
| 
212
 | 
31
 | 
 
 | 
  
100
  
 | 
  
31
  
 | 
  
0
  
 | 
95
 | 
   my $Objects = shift->{objects} // [];  | 
| 
213
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
214
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
   my @Lines;  | 
| 
215
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
   for my $Card (@$Objects) {  | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # We group properties in the same group together, track if we've  | 
| 
217
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #  already output a property  | 
| 
218
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     my %DoneProps;  | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
220
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
     my $Props = $Card->{properties};  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
222
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Order the properties  | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my @PropKeys = sort {  | 
| 
224
 | 
16
 | 
  
 50
  
 | 
  
100
  
 | 
 
 | 
 
 | 
65
 | 
       ($PropOutputOrder{$a} // 1000) <=> ($PropOutputOrder{$b} // 1000)  | 
| 
 
 | 
298
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
795
 | 
    | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         || $a cmp $b  | 
| 
226
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } keys %$Props;  | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Make sure items in the same group are output together  | 
| 
229
 | 
16
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
40
 | 
     my $Groups = $Card->{groups} || do {  | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       my %Groups;  | 
| 
231
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       for (map { @$_ } values %$Props) {  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	push @{$Groups{$_->{group}}}, $_ if $_->{group};  | 
| 
233
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       \%Groups;  | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     };  | 
| 
236
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
237
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Generate output list  | 
| 
238
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
     my @OutputProps;  | 
| 
239
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
     for my $PropKey (@PropKeys) {  | 
| 
240
 | 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
78
 | 
       my @PropVals = @{$Props->{$PropKey}};  | 
| 
 
 | 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
124
 | 
    | 
| 
241
 | 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
94
 | 
       for my $PropVal (@PropVals) {  | 
| 
242
 | 
146
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
275
 | 
         next if $DoneProps{"$PropVal"}++;  | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
244
 | 
137
 | 
 
 | 
 
 | 
 
 | 
 
 | 
94
 | 
         push @OutputProps, $PropVal;  | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # If it has a group, output all values in that group together  | 
| 
247
 | 
137
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
215
 | 
         if (my $Group = $PropVal->{group}) {  | 
| 
248
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
           push @OutputProps, grep { !$DoneProps{"$_"}++ } @{$Groups->{$Group}};  | 
| 
 
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
34
 | 
    | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
253
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
     my $Type = uc $Card->{type};  | 
| 
254
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
     push @Lines, ("BEGIN:" . $Type);  | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
256
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
     for (@OutputProps) {  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # Skip deleted or synthetic properties  | 
| 
258
 | 
146
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
452
 | 
       next if $_->{deleted} || $_->{name} eq 'online';  | 
| 
259
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
260
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
110
 | 
       my $Binary = $_->{binary};  | 
| 
261
 | 
146
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
161
 | 
       if ($Binary) {  | 
| 
262
 | 
  
0
  
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
0
 | 
         my $Encoding = ($_->{params}->{encoding} //= []);  | 
| 
263
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         push @$Encoding, "b" if !@$Encoding;  | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
266
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
112
 | 
       my $LName = $_->{name};  | 
| 
267
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
94
 | 
       my $Group = $_->{group};  | 
| 
268
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # rfc6350 3.3 - it is RECOMMENDED that property and parameter names be upper-case on output.  | 
| 
270
 | 
146
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
242
 | 
       my $Line = ($Group ? (uc $Group . ".") : "") . uc $LName;  | 
| 
271
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
272
 | 
146
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
96
 | 
       while (my ($Param, $ParamVals) = each %{$_->{params} // {}}) {  | 
| 
 
 | 
231
 | 
 
 | 
 
 | 
 
 | 
 
 | 
719
 | 
    | 
| 
273
 | 
85
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
104
 | 
         if (!defined $ParamVals) {  | 
| 
274
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
           $Line .= ";" . uc($Param);  | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
276
 | 
85
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
137
 | 
         for (ref($ParamVals) ? @$ParamVals : $ParamVals) {  | 
| 
277
 | 
114
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
133
 | 
           my $PV = $_ // next; # Modify copy  | 
| 
278
 | 
114
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
135
 | 
           $PV =~ s/\n/\\N/g if $Param eq 'label';  | 
| 
279
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
120
 | 
           $PV =~ s/([\n^"])/'^' . $RFC6868RevMap{$1}/ge;  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
280
 | 
114
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
162
 | 
           $PV = '"' . $PV . '"' if $PV =~ /\W/;  | 
| 
281
 | 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
229
 | 
           $Line .= ";" . uc($Param) . "=" . $PV;  | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
284
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
178
 | 
       $Line .= ":";  | 
| 
285
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
286
 | 
146
 | 
 
 | 
  
 66
  
 | 
 
 | 
 
 | 
266
 | 
       my $Value = $_->{values} || $_->{value};  | 
| 
287
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
288
 | 
146
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
150
 | 
       if ($_->{binary}) {  | 
| 
289
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
         $Value = encode_base64($Value, '');  | 
| 
290
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       } else {  | 
| 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my @Values = map {  | 
| 
293
 | 
146
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
192
 | 
           my $V = ref($_) ? $$_ : $_; # Modify copy  | 
| 
 
 | 
253
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
253
 | 
    | 
| 
294
 | 
253
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
290
 | 
           $V //= '';  | 
| 
295
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           # rfc6350 3.4 (v4, assume clarifies many v3 semantics)  | 
| 
296
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           # - a SEMICOLON in a field of such a "compound" property MUST be  | 
| 
297
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           #   escaped with a BACKSLASH character  | 
| 
298
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           # - a COMMA character in one of a field's values MUST be escaped  | 
| 
299
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           #   with a BACKSLASH character  | 
| 
300
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           # - BACKSLASH characters in values MUST be escaped with a BACKSLASH  | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           #   character.  | 
| 
302
 | 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
306
 | 
           $V =~ s/([\,\;\\])/\\$1/g;  | 
| 
303
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           # - NEWLINE (U+000A) characters in values MUST be encoded  | 
| 
304
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           #   by two characters: a BACKSLASH followed by either an 'n' (U+006E)  | 
| 
305
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           #   or an 'N' (U+004E).  | 
| 
306
 | 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
223
 | 
           $V =~ s/\n/\\n/g;  | 
| 
307
 | 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
328
 | 
           $V;  | 
| 
308
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } ref $Value ? @$Value : $Value;  | 
| 
309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
310
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
204
 | 
         $Value = join ";", @Values;  | 
| 
311
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
312
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # Stripped v4 proto prefix, add it back  | 
| 
313
 | 
146
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
243
 | 
         if (my $ProtoStrip = $_->{proto_strip}) {  | 
| 
314
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
           $Value = $ProtoStrip . $Value;  | 
| 
315
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }  | 
| 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # If it's a perl unicode string, make it utf-8 bytes  | 
| 
318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #if (utf8::is_utf8($Value)) {  | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
           #$Value = encode_utf8($Value);  | 
| 
320
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         #}  | 
| 
321
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
323
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
125
 | 
       $Line .= $Value;  | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
325
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
187
 | 
       push @Lines, foldline($Line);  | 
| 
326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
327
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
328
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
40
 | 
     push @Lines, hash2vcardlines_pp($Card);  | 
| 
329
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
330
 | 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
61
 | 
     push @Lines, "END:" . $Type;  | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
332
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
333
 | 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
58
 | 
   return @Lines;  | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub foldline {  | 
| 
337
 | 
146
 | 
 
 | 
 
 | 
  
146
  
 | 
  
0
  
 | 
122
 | 
   local $_ = shift;  | 
| 
338
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
339
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Fold at every \n, regardless of position  | 
| 
340
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Try folding on at whitespace boundaries after 60 chars first  | 
| 
341
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # Otherwise fold to 75 chars, but don't split utf-8 unicode char or end with a \  | 
| 
342
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
92
 | 
   my @Out;  | 
| 
343
 | 
146
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
917
 | 
   while (/\G(.{0,75}?\\n)/gc || /\G(.{60,75})(?<=[^\n\t ])(?=[\n\t ])/gc || /\G(.{0,74}[^\\])(?![\x80-\xbf])/gc) {  | 
| 
 
 | 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
344
 | 
191
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1064
 | 
     push @Out, (@Out ? " " . $1 : $1);  | 
| 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
346
 | 
146
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
310
 | 
   push @Out, " " . substr($_, pos($_)) if pos $_ != length $_;  | 
| 
347
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
348
 | 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
274
 | 
   return @Out;  | 
| 
349
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
351
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # }}}  | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
353
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
354
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  | 
| 
356
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 __END__  |