|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Copyright (C) 2009-2021  Alex Schroeder   | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # This program is free software: you can redistribute it and/or modify it under  | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # the terms of the GNU Affero General Public License as published by the Free  | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Software Foundation, either version 3 of the License, or (at your option) any  | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # later version.  | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # This program is distributed in the hope that it will be useful, but WITHOUT  | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS  | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more  | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # details.  | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #  | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # You should have received a copy of the GNU Affero General Public License along  | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # with this program. If not, see .  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =encoding utf8  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 NAME  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Game::TextMapper::Mapper - a text map parser and builder  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SYNOPSIS  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     use Modern::Perl;  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     use Game::TextMapper::Mapper::Hex;  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $map = <
 | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     0101 forest  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     include default.txt  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     EOT  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $svg = Game::TextMapper::Mapper::Hex->new(dist_dir => 'share')  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       ->initialize($map)  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       ->svg();  | 
| 
33
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     print $svg;  | 
| 
34
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
35
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 DESCRIPTION  | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This class knows how to parse a text containing a map description into SVG  | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 definitions, and regions. Once the map is built, this class knows how to  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 generate the SVG for the entire map.  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The details depend on whether the map is a hex map or a square map. You should  | 
| 
42
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 use the appropriate class instead of this one: L  | 
| 
43
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 or L.  | 
| 
44
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
45
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
46
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Game::TextMapper::Mapper;  | 
| 
48
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
490
 | 
 use Game::TextMapper::Log;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
    | 
| 
49
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
5
 | 
 use Modern::Perl '2018';  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
    | 
| 
50
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
103
 | 
 use Mojo::UserAgent;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
51
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
28
 | 
 use Mojo::Base -base;  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
    | 
| 
52
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
561
 | 
 use File::Slurper qw(read_text);  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2740
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
    | 
| 
53
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
14
 | 
 use Encode qw(decode_utf8);  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
    | 
| 
54
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
 
 | 
454
 | 
 use File::ShareDir 'dist_dir';  | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22136
 | 
    | 
| 
 
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4399
 | 
    | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 ATTRIBUTES  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 dist_dir  | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 You need to pass this during instantiation so that the mapper knows where to  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 find files it needs to include.  | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'local_files';  | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'dist_dir';  | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'map';  | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'regions' => sub { [] };  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'attributes' => sub { {} };  | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'defs' => sub { [] };  | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'path' => sub { {} };  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'lines' => sub { [] };  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'things' => sub { [] };  | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'path_attributes' => sub { {} };  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'text_attributes' => '';  | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'glow_attributes' => '';  | 
| 
77
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'label_attributes' => '';  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'messages' => sub { [] };  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'seen' => sub { {} };  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'license' => '';  | 
| 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'other' => sub { [] };  | 
| 
82
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'url' => '';  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 has 'offset' => sub { [] };  | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $log = Game::TextMapper::Log->get;  | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub example {  | 
| 
88
 | 
1
 | 
 
 | 
 
 | 
  
1
  
 | 
  
0
  
 | 
5
 | 
   return <<"EOT";  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0101 mountain "mountain"  | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0102 swamp "swamp"  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0103 hill "hill"  | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0104 forest "forest"  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0201 empty pyramid "pyramid"  | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0202 tundra "tundra"  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0203 coast "coast"  | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0204 empty house "house"  | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0301 woodland "woodland"  | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0302 wetland "wetland"  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0303 plain "plain"  | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0304 sea "sea"  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0401 hill tower "tower"  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0402 sand house "house"  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0403 jungle "jungle"  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0501 mountain cave "cave"  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0502 sand "sand"  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0503 hill castle "castle"  | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0205-0103-0202-0303-0402 road  | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0101-0203 river  | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 0401-0303-0403 border  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 include default.txt  | 
| 
111
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 license Public Domain  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 EOT  | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
115
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 METHODS  | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 initialize($map)  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Call this to load a map into the mapper.  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub initialize {  | 
| 
124
 | 
10
 | 
 
 | 
 
 | 
  
10
  
 | 
  
1
  
 | 
103
 | 
   my ($self, $map) = @_;  | 
| 
125
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
89
 | 
   $map =~ s/-/-/g; # -- are invalid in source comments...  | 
| 
126
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
55
 | 
   $self->map($map);  | 
| 
127
 | 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1524
 | 
   $self->process(split(/\r?\n/, $map));  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
130
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub process {  | 
| 
131
 | 
18
 | 
 
 | 
 
 | 
  
18
  
 | 
  
0
  
 | 
3291
 | 
   my $self = shift;  | 
| 
132
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
45
 | 
   my $line_id = 0;  | 
| 
133
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
45
 | 
   foreach (@_) {  | 
| 
134
 | 
3879
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
27128
 | 
     if (/^(-?\d\d)(-?\d\d)(\d\d)?\s+(.*)/) {  | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
135
 | 
2502
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
8445
 | 
       my $region = $self->make_region(x => $1, y => $2, z => $3||'00', map => $self);  | 
| 
136
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17456
 | 
       my $rest = $4;  | 
| 
137
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6102
 | 
       while (my ($tag, $label, $size) = $rest =~ /\b([a-z]+)=["“]([^"”]+)["”]\s*(\d+)?/) {  | 
| 
138
 | 
82
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
148
 | 
 	if ($tag eq 'name') {  | 
| 
139
 | 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
88
 | 
 	  $region->label($label);  | 
| 
140
 | 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
201
 | 
 	  $region->size($size);  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
142
 | 
82
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1376
 | 
 	$rest =~ s/\b([a-z]+)=["“]([^"”]+)["”]\s*(\d+)?//;  | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
144
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4814
 | 
       while (my ($label, $size) = $rest =~ /["“]([^"”]+)["”]\s*(\d+)?/) {  | 
| 
145
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
 	$region->label($label);  | 
| 
146
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
78
 | 
 	$region->size($size);  | 
| 
147
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
54
 | 
 	$rest =~ s/["“]([^"”]+)["”]\s*(\d+)?//;  | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
149
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6012
 | 
       my @types = split(/\s+/, $rest);  | 
| 
150
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5608
 | 
       $region->type(\@types);  | 
| 
151
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
10826
 | 
       push(@{$self->regions}, $region);  | 
| 
 
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3799
 | 
    | 
| 
152
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8409
 | 
       push(@{$self->things}, $region);  | 
| 
 
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3804
 | 
    | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^(-?\d\d-?\d\d(?:\d\d)?(?:--?\d\d-?\d\d(?:\d\d)?)+)\s+(\S+)\s*(?:["“](.+)["”])?/) {  | 
| 
154
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
986
 | 
       my $line = $self->make_line(map => $self);  | 
| 
155
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2249
 | 
       my $str = $1;  | 
| 
156
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
807
 | 
       $line->type($2);  | 
| 
157
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2020
 | 
       $line->label($3);  | 
| 
158
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2095
 | 
       $line->id('line' . $line_id++);  | 
| 
159
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1505
 | 
       my @points;  | 
| 
160
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1187
 | 
       while ($str =~ /\G(-?\d\d)(-?\d\d)(\d\d)?-?/cg) {  | 
| 
161
 | 
2747
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
23547
 | 
 	push(@points, Game::TextMapper::Point->new(x => $1, y => $2, z => $3||'00'));  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
163
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3074
 | 
       $line->points(\@points);  | 
| 
164
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1591
 | 
       push(@{$self->lines}, $line);  | 
| 
 
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
618
 | 
    | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^(\S+)\s+attributes\s+(.*)/) {  | 
| 
166
 | 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
280
 | 
       $self->attributes->{$1} = $2;  | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^(\S+)\s+lib\s+(.*)/) {  | 
| 
168
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
       $self->def(qq{$2});  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^(\S+)\s+xml\s+(.*)/) {  | 
| 
170
 | 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
86
 | 
       $self->def(qq{$2});  | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^(<.*>)/) {  | 
| 
172
 | 
443
 | 
 
 | 
 
 | 
 
 | 
 
 | 
698
 | 
       $self->def($1);  | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^(\S+)\s+path\s+attributes\s+(.*)/) {  | 
| 
174
 | 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
97
 | 
       $self->path_attributes->{$1} = $2;  | 
| 
175
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^(\S+)\s+path\s+(.*)/) {  | 
| 
176
 | 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
       $self->path->{$1} = $2;  | 
| 
177
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^text\s+(.*)/) {  | 
| 
178
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
       $self->text_attributes($1);  | 
| 
179
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^glow\s+(.*)/) {  | 
| 
180
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
       $self->glow_attributes($1);  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^label\s+(.*)/) {  | 
| 
182
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
       $self->label_attributes($1);  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^license\s+(.*)/) {  | 
| 
184
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
       $self->license($1);  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^other\s+(.*)/) {  | 
| 
186
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
       push(@{$self->other()}, $1);  | 
| 
 
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
    | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^url\s+(\S+)/) {  | 
| 
188
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9
 | 
       $self->url($1);  | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } elsif (/^include\s+(\S*)/) {  | 
| 
190
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
16
 | 
       if (scalar keys %{$self->seen} > 5) {  | 
| 
 
 | 
8
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
53
 | 
    | 
| 
191
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	push(@{$self->messages},  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
192
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	     "Includes are limited to five to prevent loops");  | 
| 
193
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       } elsif (not $self->seen->{$1}) {  | 
| 
194
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
96
 | 
 	my $location = $1;  | 
| 
195
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
 	$self->seen->{$location} = 1;  | 
| 
196
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
 	my $path;  | 
| 
197
 | 
8
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
60
 | 
 	if (index($location, '/') == -1 and -f ($path = Mojo::File->new($self->dist_dir, $location))) {  | 
| 
 
 | 
 
 | 
  
  0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
 
 | 
 
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
198
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  # without a slash, it could be a file from dist_dir  | 
| 
199
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
666
 | 
 	  $log->debug("Reading $location");  | 
| 
200
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
138
 | 
 	  $self->process(split(/\n/, decode_utf8($path->slurp())));  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} elsif ($self->local_files and -f ($path = Mojo::File->new($location))) {  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  # it could also be a local file in the same directory, but only if  | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  # called from the render command (which sets local_files)  | 
| 
204
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  $log->debug("Reading $location");  | 
| 
205
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  $self->process(split(/\n/, decode_utf8($path->slurp())));  | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} elsif ($location =~ /^https?:/) {  | 
| 
207
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  $log->debug("Getting $location");  | 
| 
208
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  my $ua = Mojo::UserAgent->new;  | 
| 
209
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  my $response = $ua->get($location)->result;  | 
| 
210
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  if ($response->is_success) {  | 
| 
211
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    $self->process(split(/\n/, $response->text));  | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  } else {  | 
| 
213
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    push(@{$self->messages}, "Getting $location: " . $response->status_line);  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  }  | 
| 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} elsif ($self->dist_dir =~ /^https?:/) {  | 
| 
216
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  my $url = $self->dist_dir;  | 
| 
217
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  $url .= '/' unless $url =~ /\/$/;  | 
| 
218
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  $url .= $location;  | 
| 
219
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  $log->debug("Getting $url");  | 
| 
220
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  my $ua = Mojo::UserAgent->new;  | 
| 
221
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  my $response = $ua->get($url)->result;  | 
| 
222
 | 
  
0
  
 | 
  
  0
  
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  if ($response->is_success) {  | 
| 
223
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    $self->process(split(/\n/, $response->text));  | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  } else {  | 
| 
225
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	    push(@{$self->messages}, "Getting $url: " . $response->status_line);  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
226
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	  }  | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	} else {  | 
| 
228
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  $log->warn("No library '$location' in " . $self->dist_dir);  | 
| 
229
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
 	  push(@{$self->messages}, "Library '$location' is must be an existing file on the server or a HTTP/HTTPS URL");  | 
| 
 
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
    | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 	}  | 
| 
231
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
233
 | 
319
 | 
  
 50
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
905
 | 
       $log->debug("Did not parse $_") if $_ and not /^\s*#/;  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
236
 | 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
222
 | 
   return $self;  | 
| 
237
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
238
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub def {  | 
| 
240
 | 
469
 | 
 
 | 
 
 | 
  
469
  
 | 
  
0
  
 | 
1329
 | 
   my ($self, $svg) = @_;  | 
| 
241
 | 
469
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1965
 | 
   $svg =~ s/>\s+>
 | 
| 
242
 | 
469
 | 
 
 | 
 
 | 
 
 | 
 
 | 
549
 | 
   push(@{$self->defs}, $svg);  | 
| 
 
 | 
469
 | 
 
 | 
 
 | 
 
 | 
 
 | 
772
 | 
    | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub merge_attributes {  | 
| 
246
 | 
494
 | 
 
 | 
 
 | 
  
494
  
 | 
  
0
  
 | 
2271
 | 
   my %attr = ();  | 
| 
247
 | 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
602
 | 
   for my $attr (@_) {  | 
| 
248
 | 
741
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
1365
 | 
     if ($attr) {  | 
| 
249
 | 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
352
 | 
       while ($attr =~ /(\S+)=((["']).*?\3)/g) {  | 
| 
250
 | 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
410
 | 
         $attr{$1} = $2;  | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
254
 | 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1023
 | 
   return join(' ', map { $_ . '=' . $attr{$_} } sort keys %attr);  | 
| 
 
 | 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
391
 | 
    | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub svg_header {  | 
| 
258
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
0
  
 | 
21
 | 
   my ($self) = @_;  | 
| 
259
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
260
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
   my $header = qq{  | 
| 
261
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
  | 
| 
262
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
      xmlns:xlink="http://www.w3.org/1999/xlink"  | 
| 
263
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 };  | 
| 
264
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
11
 | 
   return $header . "\n" unless @{$self->regions};  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
    | 
| 
265
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
47
 | 
   my $maxz = 0;  | 
| 
266
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
   foreach my $region (@{$self->regions}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
    | 
| 
267
 | 
2502
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
9253
 | 
     $maxz = $region->z if $region->z > $maxz;  | 
| 
268
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # These are required to calculate the viewBox for the SVG. Min and max X are  | 
| 
270
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # what you would expect. Min and max Y are different, however, since we want  | 
| 
271
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # to count all the rows on all the levels, plus an extra separator between  | 
| 
272
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # them. Thus, min y is the min y of the first level, and max y is the min y of  | 
| 
273
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # the first level + 1 for every level beyond the first, + all the rows for  | 
| 
274
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # each level.  | 
| 
275
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
73
 | 
   my $min_x_overall;  | 
| 
276
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   my $max_x_overall;  | 
| 
277
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   my $min_y_overall;  | 
| 
278
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
   my $max_y_overall;  | 
| 
279
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
   for my $z (0 .. $maxz) {  | 
| 
280
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
     my ($minx, $miny, $maxx, $maxy);  | 
| 
281
 | 
9
 | 
 
 | 
  
 50
  
 | 
 
 | 
 
 | 
72
 | 
     $self->offset->[$z] = $max_y_overall // 0;  | 
| 
282
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
     foreach my $region (@{$self->regions}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
283
 | 
2502
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
10727
 | 
       next unless $region->z == $z;  | 
| 
284
 | 
2502
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
10255
 | 
       $minx = $region->x unless defined $minx and $minx <= $region->x;  | 
| 
285
 | 
2502
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
11183
 | 
       $maxx = $region->x unless defined $maxx and $maxx >= $region->x;  | 
| 
286
 | 
2502
 | 
  
100
  
 | 
  
 66
  
 | 
 
 | 
 
 | 
11699
 | 
       $miny = $region->y unless defined $miny and $miny <= $region->y;  | 
| 
287
 | 
2502
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
11085
 | 
       $maxy = $region->y unless defined $maxy and $maxy >= $region->y;  | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
289
 | 
9
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
62
 | 
     $min_x_overall = $minx unless defined $min_x_overall and $minx >= $min_x_overall;  | 
| 
290
 | 
9
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
20
 | 
     $max_x_overall = $maxx unless defined $min_y_overall and $maxx <= $max_x_overall;;  | 
| 
291
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
19
 | 
     $min_y_overall = $miny unless defined $min_y_overall; # first row of the first level  | 
| 
292
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
20
 | 
     $max_y_overall = $miny unless defined $max_y_overall; # also (!) first row of the first level  | 
| 
293
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
24
 | 
     $max_y_overall += 1 if $z > 0; # plus a separator row for every extra level  | 
| 
294
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
     $max_y_overall += 1 + $maxy - $miny; # plus the number of rows for every level  | 
| 
295
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
296
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
57
 | 
   my ($vx1, $vy1, $vx2, $vy2) = $self->viewbox($min_x_overall, $min_y_overall, $max_x_overall, $max_y_overall);  | 
| 
297
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
   my ($width, $height) = ($vx2 - $vx1, $vy2 - $vy1);  | 
| 
298
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
56
 | 
   $header .= qq{     viewBox="$vx1 $vy1 $width $height">\n};  | 
| 
299
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
39
 | 
   $header .= qq{     \n};  | 
| 
300
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
   return $header;  | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
302
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
303
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub svg_defs {  | 
| 
304
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
0
  
 | 
15
 | 
   my ($self) = @_;  | 
| 
305
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # All the definitions are included by default.  | 
| 
306
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21
 | 
   my $doc = "  \n";  | 
| 
307
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
17
 | 
   $doc .= "    " . join("\n    ", @{$self->defs}, "") if @{$self->defs};  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
    | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
    | 
| 
308
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # collect region types from attributess and paths in case the sets don't overlap  | 
| 
309
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
233
 | 
   my %types = ();  | 
| 
310
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
   foreach my $region (@{$self->regions}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
    | 
| 
311
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2927
 | 
     foreach my $type (@{$region->type}) {  | 
| 
 
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3396
 | 
    | 
| 
312
 | 
4099
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8914
 | 
       $types{$type} = 1;  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
314
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
315
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
   foreach my $line (@{$self->lines}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
    | 
| 
316
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1155
 | 
     $types{$line->type} = 1;  | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # now go through them all  | 
| 
319
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
143
 | 
   foreach my $type (sort keys %types) {  | 
| 
320
 | 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
420
 | 
     my $path = $self->path->{$type};  | 
| 
321
 | 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
841
 | 
     my $attributes = merge_attributes($self->attributes->{$type});  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $path_attributes = merge_attributes($self->path_attributes->{'default'},  | 
| 
323
 | 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
504
 | 
 					   $self->path_attributes->{$type});  | 
| 
324
 | 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
514
 | 
     my $glow_attributes = $self->glow_attributes;  | 
| 
325
 | 
247
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
1226
 | 
     if ($path || $attributes) {  | 
| 
326
 | 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
125
 | 
       $doc .= qq{    \n};  | 
| 
327
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # just shapes get a glow such, eg. a house (must come first)  | 
| 
328
 | 
53
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
123
 | 
       if ($path && !$attributes) {  | 
| 
329
 | 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
 	$doc .= qq{      \n}  | 
| 
330
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # region with attributes get a shape (square or hex), eg. plains and grass  | 
| 
332
 | 
53
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
82
 | 
       if ($attributes) {  | 
| 
333
 | 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
107
 | 
 	$doc .= "      " . $self->shape($attributes) . "\n";  | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # and now the attributes themselves the shape itself  | 
| 
336
 | 
53
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
109
 | 
       if ($path) {  | 
| 
337
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
       $doc .= qq{      \n}  | 
| 
338
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       }  | 
| 
339
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # close  | 
| 
340
 | 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
102
 | 
       $doc .= qq{    \n};  | 
| 
341
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     } else {  | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
       # nothing  | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
345
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
242
 | 
   $doc .= qq{  \n};  | 
| 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
347
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
348
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub svg_backgrounds {  | 
| 
349
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
0
  
 | 
19
 | 
   my $self = shift;  | 
| 
350
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
   my $doc = qq{  \n};  | 
| 
351
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
   foreach my $thing (@{$self->things}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
25
 | 
    | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # make a copy  | 
| 
353
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11534
 | 
     my @types = @{$thing->type};  | 
| 
 
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3711
 | 
    | 
| 
354
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # keep attributes  | 
| 
355
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8624
 | 
     $thing->type([grep { $self->attributes->{$_} } @{$thing->type}]);  | 
| 
 
 | 
4099
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13566
 | 
    | 
| 
 
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3928
 | 
    | 
| 
356
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17967
 | 
     $doc .= $thing->svg($self->offset);  | 
| 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # reset copy  | 
| 
358
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5191
 | 
     $thing->type(\@types);  | 
| 
359
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
360
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
59
 | 
   $doc .= qq{  \n};  | 
| 
361
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
478
 | 
   return $doc;  | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
364
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub svg_things {  | 
| 
365
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
0
  
 | 
15
 | 
   my $self = shift;  | 
| 
366
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
27
 | 
   my $doc = qq{  \n};  | 
| 
367
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
   foreach my $thing (@{$self->things}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # drop attributes  | 
| 
369
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2865
 | 
     $thing->type([grep { not $self->attributes->{$_} } @{$thing->type}]);  | 
| 
 
 | 
4099
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14876
 | 
    | 
| 
 
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3732
 | 
    | 
| 
370
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17942
 | 
     $doc .= $thing->svg($self->offset);  | 
| 
371
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
372
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
   $doc .= qq{  \n};  | 
| 
373
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
284
 | 
   return $doc;  | 
| 
374
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub svg_coordinates {  | 
| 
377
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
0
  
 | 
18
 | 
   my $self = shift;  | 
| 
378
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
   my $doc = qq{  \n};  | 
| 
379
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
   foreach my $region (@{$self->regions}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
    | 
| 
380
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
4618
 | 
     $doc .= $region->svg_coordinates($self->offset);  | 
| 
381
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
382
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
   $doc .= qq{  \n};  | 
| 
383
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
409
 | 
   return $doc;  | 
| 
384
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
385
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
386
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub svg_lines {  | 
| 
387
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
0
  
 | 
22
 | 
   my $self = shift;  | 
| 
388
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
   my $doc = qq{  \n};  | 
| 
389
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14
 | 
   foreach my $line (@{$self->lines}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
    | 
| 
390
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
851
 | 
     $doc .= $line->svg($self->offset);  | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
392
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
   $doc .= qq{  \n};  | 
| 
393
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
200
 | 
   return $doc;  | 
| 
394
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
395
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
396
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub svg_regions {  | 
| 
397
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
0
  
 | 
26
 | 
   my $self = shift;  | 
| 
398
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
18
 | 
   my $doc = qq{  \n};  | 
| 
399
 | 
9
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
29
 | 
   my $attributes = $self->attributes->{default} || qq{fill="none"};  | 
| 
400
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
70
 | 
   foreach my $region (@{$self->regions}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
24
 | 
    | 
| 
401
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23122
 | 
     $doc .= $region->svg_region($attributes, $self->offset);  | 
| 
402
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
403
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
709
 | 
   $doc .= qq{  \n};  | 
| 
404
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
405
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
406
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub svg_line_labels {  | 
| 
407
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
0
  
 | 
19
 | 
   my $self = shift;  | 
| 
408
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
19
 | 
   my $doc = qq{  \n};  | 
| 
409
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
   foreach my $line (@{$self->lines}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
410
 | 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1559
 | 
     $doc .= $line->svg_label($self->offset);  | 
| 
411
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
412
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64
 | 
   $doc .= qq{  \n};  | 
| 
413
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
   return $doc;  | 
| 
414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
415
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub svg_labels {  | 
| 
417
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
0
  
 | 
18
 | 
   my $self = shift;  | 
| 
418
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
   my $doc = qq{  \n};  | 
| 
419
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
17
 | 
   foreach my $region (@{$self->regions}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
420
 | 
2502
 | 
 
 | 
 
 | 
 
 | 
 
 | 
9849
 | 
     $doc .= $region->svg_label($self->url, $self->offset);  | 
| 
421
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
422
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
43
 | 
   $doc .= qq{  \n};  | 
| 
423
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30
 | 
   return $doc;  | 
| 
424
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
425
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 svg()  | 
| 
427
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This method generates the SVG once the map is initialized.  | 
| 
429
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
430
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
431
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sub svg {  | 
| 
433
 | 
9
 | 
 
 | 
 
 | 
  
9
  
 | 
  
1
  
 | 
23
 | 
   my ($self) = @_;  | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
435
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
   my $doc = $self->svg_header();  | 
| 
436
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
35
 | 
   $doc .= $self->svg_defs();  | 
| 
437
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
69
 | 
   $doc .= $self->svg_backgrounds(); # opaque backgrounds  | 
| 
438
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
109
 | 
   $doc .= $self->svg_lines();  | 
| 
439
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
57
 | 
   $doc .= $self->svg_things(); # icons, lines  | 
| 
440
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
48
 | 
   $doc .= $self->svg_coordinates();  | 
| 
441
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
54
 | 
   $doc .= $self->svg_regions();  | 
| 
442
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
58
 | 
   $doc .= $self->svg_line_labels();  | 
| 
443
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
53
 | 
   $doc .= $self->svg_labels();  | 
| 
444
 | 
9
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
36
 | 
   $doc .= $self->license() ||'';  | 
| 
445
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
64
 | 
   $doc .= join("\n", @{$self->other()}) . "\n";  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
33
 | 
    | 
| 
446
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
447
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # error messages  | 
| 
448
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
   my $y = 10;  | 
| 
449
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
22
 | 
   foreach my $msg (@{$self->messages}) {  | 
| 
 
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
58
 | 
    | 
| 
450
 | 
  
0
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $doc .= "  $msg\n";  | 
| 
451
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
     $y += 10;  | 
| 
452
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   }  | 
| 
453
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
454
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # source code (comments may not include -- for SGML compatibility!)  | 
| 
455
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   # https://stackoverflow.com/questions/10842131/xml-comments-and  | 
| 
456
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
   my $source = $self->map();  | 
| 
457
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
149
 | 
   $source =~ s/--/--/g;  | 
| 
458
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
147
 | 
   $doc .= "\n";  | 
| 
459
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
   $doc .= qq{\n};  | 
| 
460
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
461
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
869
 | 
   return $doc;  | 
| 
462
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }  | 
| 
463
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
464
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SEE ALSO  | 
| 
465
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
466
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L is for hex maps.  | 
| 
467
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
468
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 L is for square maps.  | 
| 
469
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut  | 
| 
471
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
472
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  |