|  line  | 
 stmt  | 
 bran  | 
 cond  | 
 sub  | 
 pod  | 
 time  | 
 code  | 
| 
1
 | 
  
 
  
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Weather::GHCN::Options.pm - class for GHCN options
  | 
| 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
3
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## no critic (Documentation::RequirePodAtEnd)
  | 
| 
4
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 NAME
  | 
| 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Weather::GHCN::Options - create and manage option lists/objects used by GHCN modules and scripts
  | 
| 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 VERSION  | 
| 
10
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
    | 
| 
11
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 version v0.0.010  | 
| 
12
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
13
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 SYNOPSIS
  | 
| 
14
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
15
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
   use Weather::GHCN::Options;
  | 
| 
16
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
17
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
18
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 DESCRIPTION
  | 
| 
19
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
20
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The B module provides a class and methods that are
  | 
| 
21
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 used within GHCN modules or from application scripts that use GHCN
  | 
| 
22
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 modules to create and manage options that determine the behaviour of
  | 
| 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 GHCN methods.
  | 
| 
24
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
25
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The module is primarily for use by module Weather::GHCN::StationTable.
  | 
| 
26
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
27
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
28
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
29
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # these are needed because perlcritic fails to detect that Object::Pad handles these things
  | 
| 
30
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## no critic [ValuesAndExpressions::ProhibitVersionStrings]
  | 
| 
31
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## no critic [TestingAndDebugging::RequireUseWarnings]
  | 
| 
32
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
33
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
2207
 | 
 use v5.18;  # minimum for Object::Pad
  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
20
 | 
    | 
| 
34
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
29
 | 
 use warnings;
  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
8
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
184
 | 
    | 
| 
35
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
28
 | 
 use Object::Pad 0.66 qw( :experimental(init_expr) );
  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
79
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28
 | 
    | 
| 
36
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
37
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 package Weather::GHCN::Options;
  | 
| 
38
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 class   Weather::GHCN::Options;
  | 
| 
39
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
40
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 our $VERSION = 'v0.0.010';  | 
| 
41
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
42
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
2048
 | 
 use Carp                qw(carp croak);
  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
327
 | 
    | 
| 
43
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
37
 | 
 use Const::Fast;
  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
36
 | 
    | 
| 
44
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
3224
 | 
 use Hash::Wrap          {-lvalue => 1, -defined => 1, -as => '_wrap_hash'};
  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
21385
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
32
 | 
    | 
| 
45
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
9810
 | 
 use Text::Abbrev;
  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
199
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
333
 | 
    | 
| 
46
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
1182
 | 
 use Weather::GHCN::CountryCodes  qw( search_country );
  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
421
 | 
    | 
| 
47
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
1029
 | 
 use Weather::GHCN::Common        qw( :all );
  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
784
 | 
    | 
| 
48
 | 
5
 | 
 
 | 
 
 | 
  
5
  
 | 
 
 | 
2847
 | 
 use YAML::Tiny;
  | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
31405
 | 
    | 
| 
 
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
30110
 | 
    | 
| 
49
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
50
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ######################################################################
  | 
| 
51
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Constants
  | 
| 
52
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ######################################################################
  | 
| 
53
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
54
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 const my $TRUE   => 1;      # perl's usual TRUE
  | 
| 
55
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 const my $FALSE  => not $TRUE; # a dual-var consisting of '' and 0
  | 
| 
56
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 const my $SPACE  => q( );
  | 
| 
57
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 const my $EMPTY  => q();
  | 
| 
58
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 const my $DASH   => q(-);
  | 
| 
59
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 const my $BAR    => q(|);
  | 
| 
60
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 const my $BANG   => q(!);
  | 
| 
61
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 const my $NEWLINE => qq(\n);
  | 
| 
62
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
63
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 const my $DEFAULT_PROFILE_FILE  => '~/.ghcn_fetch.yaml';
  | 
| 
64
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 const my $ALIAS_NAME_RE => qr{ \A [_]?[[:lower:]]+ \Z }xms;
  | 
| 
65
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 const my @REPORT_TYPE_LIST => qw(detail daily monthly yearly url curl kml stn id);
  | 
| 
66
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
67
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 METHODS
  | 
| 
68
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
69
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 new
  | 
| 
70
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
71
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Create a new Options object.
  | 
| 
72
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
73
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
74
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
75
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ######################################################################
  | 
| 
76
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Set up the default Tk::Getopt option table, which we will use for
  | 
| 
77
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # both Tk::Getopt and to derive an options list of Getopt::Long
  | 
| 
78
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # for when Tk::Getopt is not installed.
  | 
| 
79
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ######################################################################
  | 
| 
80
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
81
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## no critic [ValuesAndExpressions::ProhibitMagicNumbers]
  | 
| 
82
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## no critic [ValuesAndExpressions::ProhibitNoisyQuotes]
  | 
| 
83
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## no critic [ValuesAndExpressions::ProhibitEmptyQuotes]
  | 
| 
84
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
85
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 my $Tk_opt_table = [
  | 
| 
86
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'Basic options',
  | 
| 
87
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['location',     '=s',   undef, label => 'Filter stations by their location name (regex)'],
  | 
| 
88
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['state',        '=s',   undef, label => 'Filter stations by state or province',
  | 
| 
89
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                     alias => ['province'] ],
  | 
| 
90
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['country',      '=s',   undef, label => 'Filter station by the country they are in'],
  | 
| 
91
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['gsn',          '!',    undef, label => 'Include only GSN reference stations'],
  | 
| 
92
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['', '', '-'],
  | 
| 
93
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['report',       '=s',   '',
  | 
| 
94
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         label => 'Type of report',
  | 
| 
95
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         strict => 1,
  | 
| 
96
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         choices => [
  | 
| 
97
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             [ 'station list',       '' ],
  | 
| 
98
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             [ 'yearly summary',     'yearly' ],
  | 
| 
99
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             [ 'monthly summary',    'monthly' ],
  | 
| 
100
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             [ 'daily summary',      'daily' ],
  | 
| 
101
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             [ 'detail level',       'detail' ],
  | 
| 
102
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             [ 'station KML',        'kml' ],
  | 
| 
103
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             [ 'station url list',   'url' ],
  | 
| 
104
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             [ 'station curl list',  'curl' ],
  | 
| 
105
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             [ 'station list only',  'stn' ],
  | 
| 
106
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         ]
  | 
| 
107
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ],
  | 
| 
108
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['', '', '-'],
  | 
| 
109
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['dataonly',    '!',    undef, label => 'Only print the data table'],
  | 
| 
110
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['performance', '!',    undef, label => 'Report performance statistics'],
  | 
| 
111
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['verbose',     '!',    undef, label => 'Print information messages'],
  | 
| 
112
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
113
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'Date filters',
  | 
| 
114
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['range',       '=s',   undef, label => 'Filter selected station data by year range'],
  | 
| 
115
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['active',      '=s',   undef, label => 'Filter stations by their active year range'],
  | 
| 
116
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['partial',     '!',    undef, label => 'Allow stations only active for part of the active range'],
  | 
| 
117
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['quality',     '=i',   90,    label => 'Quality threshold (percent as an integer)'],
  | 
| 
118
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['', '','-'],
  | 
| 
119
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['fday',        '=s',   undef, label => 'Filter output to include a specific day'],
  | 
| 
120
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['fmonth',      '=s',   undef, label => 'Filter output to include a specific month'],
  | 
| 
121
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
122
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'GIS filters',
  | 
| 
123
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['gps',         '=s',   undef, label => 'Filter stations by latitude and longitude',
  | 
| 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                    help  => 'Enter decimal latitude and longitude'],
  | 
| 
125
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['radius',      '=i',   50,    label => 'Radius to search for stations near coordinates'],
  | 
| 
126
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
127
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
128
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'Analysis Options',
  | 
| 
129
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['anomalies',   '!',    undef, label => 'Provide calculated anomalies in the output'],
  | 
| 
130
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['baseline',    '=s',   '1971-2000',
  | 
| 
131
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                    label => 'Baseline year range'],
  | 
| 
132
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['precip',      '!',    undef, label => 'Include precipitation stats in the results'],
  | 
| 
133
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['tavg',        '!',    undef, label => 'Include TAVG in the results'],
  | 
| 
134
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['nogaps',      '!',    undef, label => 'Emit extra rows for missing months or days'],
  | 
| 
135
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
136
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     'Other Options',
  | 
| 
137
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['kmlcolor',    '=s',   'red', label => 'Color to use for KML placemarks' ],
  | 
| 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['profile',     '=s',   $DEFAULT_PROFILE_FILE,
  | 
| 
139
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                                    label => 'Profile file location (for option preloading)'], #, nogui => 1],
  | 
| 
140
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['cachedir',    '=s',   undef, label => 'Directory for cached files'],
  | 
| 
141
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ['refresh',    '=s',   'yearly',
  | 
| 
142
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         help => 'Refresh yearly, (default), never, always, or if N days old (N > 1)',
  | 
| 
143
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         label => 'Cache refresh option',
  | 
| 
144
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         choices => [ 'yearly', 'always', 'never', '' ],
  | 
| 
145
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ],
  | 
| 
146
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ];
  | 
| 
147
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
148
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## use critic [ValuesAndExpressions::ProhibitMagicNumbers]
  | 
| 
149
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## use critic [ValuesAndExpressions::ProhibitNoisyQuotes]
  | 
| 
150
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ## use critic [ValuesAndExpressions::ProhibitEmptyQuotes]
  | 
| 
151
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
152
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 #####################################################################
  | 
| 
153
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Class fields
  | 
| 
154
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ######################################################################
  | 
| 
155
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
156
 | 
23
 | 
 
 | 
 
 | 
  
23
  
 | 
  
1
  
 | 
7554
 | 
 field $_opt_href     :mutator;   # a hashref of merged options (with default values applied))
  | 
| 
 
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
119
 | 
    | 
| 
157
 | 
23
 | 
 
 | 
 
 | 
  
23
  
 | 
  
1
  
 | 
96
 | 
 field $_opt_obj      :mutator;   # a Hash::Wrap object derived from $_opt_href
  | 
| 
 
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
109
 | 
    | 
| 
158
 | 
285
 | 
 
 | 
 
 | 
  
285
  
 | 
  
1
  
 | 
1195
 | 
 field $_profile_href :mutator;   # a hash containing profile file options
  | 
| 
 
 | 
285
 | 
 
 | 
 
 | 
 
 | 
 
 | 
642
 | 
    | 
| 
159
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 field $_tk_opt_aref;             # the Tk:Getopt array that defines all GHCN options
  | 
| 
160
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
161
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 FIELD ACCESSORS
  | 
| 
162
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
163
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Writeable (mutator) access is provided for some fields primarily so
  | 
| 
164
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 an Options object can be tested independantly from StationTable.
  | 
| 
165
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 In general, an Options object is set by the StationTable set_options
  | 
| 
166
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 method and should not be modified directly by the consuming application
  | 
| 
167
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 using these mutators.
  | 
| 
168
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
169
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over 4
  | 
| 
170
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
171
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item opt_href
  | 
| 
172
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
173
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This writable field is set by StationTable->set_options and is a
  | 
| 
174
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 hashref of user options merged with default values.
  | 
| 
175
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
176
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 For programmatic access to option values, use of B is
  | 
| 
177
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 preferred to prevent mispellings.  (See B.)
  | 
| 
178
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
179
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item opt_obj
  | 
| 
180
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
181
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This writable field is set by StationTable->set_options and is a
  | 
| 
182
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Hash::Wrap object composed from the B hashref field.  It
  | 
| 
183
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 provides accessor field methods for user options (merged with default
  | 
| 
184
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 values).
  | 
| 
185
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
186
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Using this object, rather than B, for access to option
  | 
| 
187
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 values is safer programming choice as any misspelling of an option
  | 
| 
188
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 name will result in a run time error.  In contrast, mispelling a hash
  | 
| 
189
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 key will simply result in an undef being returned.
  | 
| 
190
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
191
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item profile_href
  | 
| 
192
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
193
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This writable field is set by StationTable->set_options and contains
  | 
| 
194
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the profile options it was given.
  | 
| 
195
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
196
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back
  | 
| 
197
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
198
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
199
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
200
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ######################################################################
  | 
| 
201
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 CLASS METHODS
  | 
| 
202
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
203
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The following class methods are supported.  Class Options uses
  | 
| 
204
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Object::Perl, so these class methods (specified using the :common
  | 
| 
205
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 method attribute) should be accessed using -> not :: because ->
  | 
| 
206
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 will shift off the $class argument and :: won't.
  | 
| 
207
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
208
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 get_tk_options_table
  | 
| 
209
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
210
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Returns:  @tk_opttable or \@tk_opttable
  | 
| 
211
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
212
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Provides access to the predefined TK::Getopt options list that define
  | 
| 
213
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the Getopt::Long arguments supported by class StationTable for user
  | 
| 
214
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 options.
  | 
| 
215
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
216
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The table is a list of lists and strings.  The strings define
  | 
| 
217
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 sections that Tk::Getopt renders as panels or tabs in the GUI it
  | 
| 
218
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 constructs. The lists contain option names and types (in Getopt::Long
  | 
| 
219
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 style) as well as default values, aliases, and labels to be displayed
  | 
| 
220
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 in the GUI, choices for multi-select options, and other extensions.
  | 
| 
221
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 See Tk::Getopt OPTTABLE ARGUMENTS for details.
  | 
| 
222
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
223
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
224
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
225
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 method get_tk_options_table :common () {
  | 
| 
226
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return wantarray ? ( $Tk_opt_table->@* ) : $Tk_opt_table;
  | 
| 
227
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
228
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
229
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 get_getopt_list
  | 
| 
230
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
231
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Returns:  @options or \@options
  | 
| 
232
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
233
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 In scalar context, return a list reference to a translation of the
  | 
| 
234
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 TK::Getopt options list into the simpler list used by Getopt::Long.
  | 
| 
235
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This gives application authors a choice between using Tk::Getopt and
  | 
| 
236
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the non-GUI and more traditional Getopt::Long.
  | 
| 
237
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
238
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 In list context, this method returns a Getopt::Long-style list
  | 
| 
239
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 options.
  | 
| 
240
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
241
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Typically, this method would be called prior to Getopt::Long in order
  | 
| 
242
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 to obtain an options list for using the StationTable class; e.g.
  | 
| 
243
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
244
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my %opt;
  | 
| 
245
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my @options = ( Weather::GHCN::Options->get_getopt_list() );
  | 
| 
246
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     GetOptions( \%opt, @options);
  | 
| 
247
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
248
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
249
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
250
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 method get_getopt_list :common () {
  | 
| 
251
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     ## no critic [ProhibitDoubleSigils]
  | 
| 
252
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my @options_text;
  | 
| 
253
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my @options_list;
  | 
| 
254
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my @options;
  | 
| 
255
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
256
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # According to https://metacpan.org/pod/Tk::Getopt -opttable
  | 
| 
257
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # should be a reference to an array containing all options.
  | 
| 
258
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Elements of this array may be strings, which indicate the
  | 
| 
259
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # beginning of a new group, or array references describing the
  | 
| 
260
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # options. The first element of this array is the name of the
  | 
| 
261
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # option, the second is the type (=s for string, =i for integer,
  | 
| 
262
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # ! for boolean, =f for float etc., see Getopt::Long) for a
  | 
| 
263
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # detailed list. The third element is optional and contains the
  | 
| 
264
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # default value (otherwise the default is undefined).
  | 
| 
265
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Further elements are optional too and describe more attributes. For a
  | 
| 
266
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # complete list of these attributes refer to "OPTTABLE ARGUMENTS".
  | 
| 
267
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
268
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     foreach my $row ( $Tk_opt_table->@* ) {
  | 
| 
269
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         next if ref $row ne 'ARRAY';
  | 
| 
270
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
271
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # pick off the first three values, then slurp the rest
  | 
| 
272
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my ($opt_kw, $opt_type, $default, @other) = $row->@*;
  | 
| 
273
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # skip the group dividers
  | 
| 
274
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         next if not $opt_kw;
  | 
| 
275
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
276
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my %h;
  | 
| 
277
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         while (my $item = shift @other) {
  | 
| 
278
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if (ref $item eq 'HASH') {
  | 
| 
279
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 while (my ($k,$v) = each $item->%*) {
  | 
| 
280
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $h{$k} = $v;
  | 
| 
281
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }
  | 
| 
282
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             } else {
  | 
| 
283
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 my $value = shift @other;
  | 
| 
284
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 $h{$item} = $value;
  | 
| 
285
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }
  | 
| 
286
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }
  | 
| 
287
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
288
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $label = $h{'label'} // $SPACE;
  | 
| 
289
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $alias_aref = $h{'alias'} // [];
  | 
| 
290
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $opt_kw_with_aliases = join $BAR, $opt_kw, $alias_aref->@*;
  | 
| 
291
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
292
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         push @options_list, $opt_kw_with_aliases . $opt_type;
  | 
| 
293
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         push @options, [$opt_kw_with_aliases, $opt_type, $label];
  | 
| 
294
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
295
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
296
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # calculate the width of the option spec column so the labels,
  | 
| 
297
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # which we print as comment in the text output, will line up
  | 
| 
298
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
299
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $colwidth = 0;
  | 
| 
300
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     foreach my $opt_aref (@options) {
  | 
| 
301
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my ($opt_kw_with_aliases, $opt_type, $label) = $opt_aref->@*;
  | 
| 
302
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $len = length( q(') . $opt_kw_with_aliases . $opt_type . q(', ) );
  | 
| 
303
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $colwidth = $len if $len > $colwidth;
  | 
| 
304
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
305
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
306
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $fmt = sprintf '%%-%ds', $colwidth;
  | 
| 
307
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
308
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     foreach my $opt_aref (@options) {
  | 
| 
309
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my ($opt_kw_with_aliases, $opt_type, $label) = $opt_aref->@*;
  | 
| 
310
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $kw = sprintf $fmt, q(') . $opt_kw_with_aliases . $opt_type . q(',);
  | 
| 
311
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         push @options_text, $kw . '# ' . $label;
  | 
| 
312
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
313
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
314
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return wantarray ? ( @options_list ) : join $NEWLINE, sort @options_text;
  | 
| 
315
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
316
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
317
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
318
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 get_option_choices ( $option )
  | 
| 
319
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
320
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Returns:  \%choices
  | 
| 
321
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
322
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Find all the options which have a multiple choice response, and return
  | 
| 
323
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 a hash keyed on the option name and with a values consisting
  | 
| 
324
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 of a hash of the valid responses as value/label pairs.
  | 
| 
325
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
326
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
327
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
328
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 method get_option_choices :common () {
  | 
| 
329
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my %choices;
  | 
| 
330
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
331
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     foreach my $row ( $Tk_opt_table->@* ) {
  | 
| 
332
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         next if ref $row ne 'ARRAY';
  | 
| 
333
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
334
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # pick off the first three values, then slurp the rest
  | 
| 
335
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my ($opt_kw, $opt_type, $default, @others) = $row->@*;
  | 
| 
336
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # skip the group dividers
  | 
| 
337
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         next if not $opt_kw;
  | 
| 
338
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
339
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $href;
  | 
| 
340
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if (@others and ref $others[0] eq 'HASH' ) {
  | 
| 
341
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $href = $others[0];
  | 
| 
342
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } elsif (@others % 2 == 0) {
  | 
| 
343
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $href = { @others };
  | 
| 
344
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {
  | 
| 
345
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             croak "*E* unable to parse opttable: @others";
  | 
| 
346
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }
  | 
| 
347
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
348
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my %hv;
  | 
| 
349
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if ( $href->{'choices'} and ref $href->{'choices'} eq 'ARRAY' ) {
  | 
| 
350
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             foreach my $slot ( $href->{'choices'}->@* ) {
  | 
| 
351
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 if (ref $slot eq 'ARRAY') {
  | 
| 
352
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $hv{ $slot->[1] } = $slot->[0];
  | 
| 
353
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }
  | 
| 
354
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 elsif (ref $slot eq $EMPTY) {
  | 
| 
355
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                     $hv{ $slot } = $TRUE;
  | 
| 
356
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 }
  | 
| 
357
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             }
  | 
| 
358
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             $choices{$opt_kw} = \%hv;
  | 
| 
359
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }
  | 
| 
360
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
361
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
362
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return \%choices;
  | 
| 
363
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
364
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
365
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 get_option_defaults
  | 
| 
366
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
367
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Returns:  \%defaults
  | 
| 
368
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
369
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Returns the option defaults, obtained from the same predefined list
  | 
| 
370
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 of lists/strings returned by get_tk_options_table.
  | 
| 
371
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
372
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
373
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
374
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 method get_option_defaults :common () {
  | 
| 
375
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
376
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my %defaults = ();
  | 
| 
377
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     foreach my $slot ($Tk_opt_table->@*) {
  | 
| 
378
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         next if ref $slot ne 'ARRAY';
  | 
| 
379
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $key = $slot->[0];
  | 
| 
380
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         next if not $key;
  | 
| 
381
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $default_value = $slot->[2];
  | 
| 
382
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         $defaults{$key} = $default_value;
  | 
| 
383
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
384
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
385
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return \%defaults;
  | 
| 
386
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
387
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
388
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 valid_report_type ($rt, \@opttable)
  | 
| 
389
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
390
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This function is used to validate the report type.  Valid values are
  | 
| 
391
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 defined in the built-in Tk options table, which can be obtained by
  | 
| 
392
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 calling:
  | 
| 
393
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
394
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my @opttable = ( Weather::GHCN::Options->get_tk_options_table() );
  | 
| 
395
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
396
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
397
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
398
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 method valid_report_type :common ($rt, $opttable_aref) {
  | 
| 
399
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $choices_href = Weather::GHCN::Options->get_option_choices;
  | 
| 
400
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return $choices_href->{'report'}->{ lc $rt };
  | 
| 
401
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
402
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
403
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 deabbrev_report_type ($rt)
  | 
| 
404
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
405
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The report types supported by the -report option can be abbrevated,
  | 
| 
406
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 so long as the abbrevation is unambiquous.  For example, 'daily' can
  | 
| 
407
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 be abbreviated to 'dail', 'dai', or 'da', but not 'd' because 'detail'
  | 
| 
408
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 is also a valid report type and 'd' would not disambiguate the two.
  | 
| 
409
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
410
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This function takes a (possibly abbreviated) report type and returns
  | 
| 
411
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 an unabbreviated report type.
  | 
| 
412
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
413
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
414
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
415
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 method deabbrev_report_type :common ($rt) {
  | 
| 
416
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my %r_abbrev = abbrev( @REPORT_TYPE_LIST );
  | 
| 
417
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         my $deabbreved = $r_abbrev{ lc $rt };
  | 
| 
418
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         return $deabbreved;
  | 
| 
419
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
420
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
421
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 valid_refresh_option ($refresh, \@opttable)
  | 
| 
422
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
423
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This function is used to validate the refresh option.  Valid values are
  | 
| 
424
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 defined in the built-in Tk options table, which can be obtained by
  | 
| 
425
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 calling:
  | 
| 
426
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
427
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my @opttable = ( Weather::GHCN::Options->get_tk_options_table() );
  | 
| 
428
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
429
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
430
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
431
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 method valid_refresh_option :common ($refresh, $opttable_aref) {
  | 
| 
432
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $choices_href = Weather::GHCN::Options->get_option_choices;
  | 
| 
433
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # we only validate the non-numeric options
  | 
| 
434
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return $TRUE if $refresh =~ m{ \A \d+ \Z }xms;
  | 
| 
435
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return $choices_href->{'refresh'}->{ lc $refresh };
  | 
| 
436
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
437
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
438
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 deabbrev_refresh_option ($refresh)
  | 
| 
439
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
440
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The refresh option values can be abbrevated, so long as the abbrevation
  | 
| 
441
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 is unambiquous.  For example, 'yearly' can
  | 
| 
442
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 be abbreviated to 'y', 'ye', 'yea', etc.
  | 
| 
443
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
444
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This function takes a (possibly abbreviated) refresh option and returns
  | 
| 
445
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 an unabbreviated refresh option.
  | 
| 
446
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
447
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
448
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
449
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 method deabbrev_refresh_option :common ($refresh) {
  | 
| 
450
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # we only deabbreviate the non-numeric options
  | 
| 
451
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return $refresh if $refresh =~ m{ \A \d+ \Z }xms;
  | 
| 
452
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my %r_abbrev = abbrev( qw(yearly never always) );
  | 
| 
453
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     my $deabbreved = $r_abbrev{ lc $refresh };
  | 
| 
454
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     return $deabbreved;
  | 
| 
455
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
456
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
457
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
458
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ######################################################################
  | 
| 
459
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head1 INSTANCE METHODS
  | 
| 
460
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
461
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over 4
  | 
| 
462
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
463
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item combine_options ( $user_opt_href, $profile_href={} )
  | 
| 
464
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
465
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Returns:  ($opt_href, $opt_obj)
  | 
| 
466
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
467
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This method takes a hash reference containing user options, and optionally
  | 
| 
468
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 a hash reference of profile options, and combines them with default
  | 
| 
469
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 values.  The end result is a complete set of all the options
  | 
| 
470
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 supported by Weather::GHCN::StationTable with user-specified options taking
  | 
| 
471
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 precedence over profile options, and profile options taking precedence
  | 
| 
472
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 over defaults.
  | 
| 
473
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
474
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This set of options is returned as both a hash reference and as a
  | 
| 
475
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Hash::Wrap object.  The latter is preferred for use by consuming
  | 
| 
476
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 applications, because it provides accessor methods for each option.
  | 
| 
477
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 In addition, an ->defined( " | 
| 
478
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 your code can determine whether an option value was set to B.
  | 
| 
479
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
480
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The advantage to using an option object rather than an option hash
  | 
| 
481
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 is that a misspelled option name will cause a runtime error.
  | 
| 
482
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
483
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back
  | 
| 
484
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
485
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
486
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
487
 | 
124
 | 
 
 | 
 
 | 
  
124
  
 | 
  
1
  
 | 
197971
 | 
 method combine_options ( $user_opt_href, $profile_href={} ) {
  | 
| 
 
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
224
 | 
    | 
| 
 
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
223
 | 
    | 
| 
 
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
203
 | 
    | 
| 
 
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
173
 | 
    | 
| 
488
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # assign the class-level tk_options_table aref, generated before BUILD, to the instance field
  | 
| 
489
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
208
 | 
     $_tk_opt_aref = $Tk_opt_table;
  | 
| 
490
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
491
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # start with the user options
  | 
| 
492
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
476
 | 
     my %merged_options = ( $user_opt_href->%* );
  | 
| 
493
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
494
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # merge in the profile options
  | 
| 
495
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
544
 | 
     while ( my ($k,$v) = each $profile_href->%* ) {
  | 
| 
496
 | 
8
 | 
 
 | 
  
 33
  
 | 
 
 | 
 
 | 
76
 | 
         $merged_options{$k} //= $v;
  | 
| 
497
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
498
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
499
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
324
 | 
     my $defaults_href = get_option_defaults();
  | 
| 
500
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
501
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # merge in the defaults
  | 
| 
502
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
554
 | 
     while ( my ($k,$v) = each $defaults_href->%* ) {
  | 
| 
503
 | 
3100
 | 
 
 | 
  
100
  
 | 
 
 | 
 
 | 
10807
 | 
         $merged_options{$k} //= $v;
  | 
| 
504
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
505
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
506
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
290
 | 
     $_opt_href = \%merged_options;
  | 
| 
507
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3318
 | 
     $_opt_obj  = _wrap_hash \%merged_options;
  | 
| 
508
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
509
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2376
 | 
     return ($_opt_href, $_opt_obj);
  | 
| 
510
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
511
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
512
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 initialize
  | 
| 
513
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
514
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Returns:  @errors
  | 
| 
515
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
516
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This method initializes options that can't simply be initialized by
  | 
| 
517
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 constants.  Specifically:
  | 
| 
518
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
519
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =over 4
  | 
| 
520
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
521
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item Aliases
  | 
| 
522
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
523
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Alias entries defined in the user profile are matched against
  | 
| 
524
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the -location option value.  If a match is found to the alias name,
  | 
| 
525
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the alias value is substituted for the location value.
  | 
| 
526
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
527
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Alias names must be lowercase letters only.  An optional underscore
  | 
| 
528
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 prefix is permitted.  Names not matching this rule will be silently
  | 
| 
529
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ignored by initialize().
  | 
| 
530
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
531
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item country
  | 
| 
532
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
533
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The B option value can be:
  | 
| 
534
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
535
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * a 2-character GEC (FIPS) country code
  | 
| 
536
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
537
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * a 3-character alpha ISO 3166 country code
  | 
| 
538
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
539
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * a 3-digit numeric ISO 3166 country number
  | 
| 
540
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
541
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * an internet domain country suffix (e.g. '.ca')
  | 
| 
542
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
543
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     * a 3-character regex string
  | 
| 
544
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
545
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 If a regex string is given, then it will be matched (unanchored and
  | 
| 
546
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 case insensitve) against country names.  If multiple matches are
  | 
| 
547
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 found, then an error is returned and the user will need to provide a
  | 
| 
548
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 more specific pattern.
  | 
| 
549
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
550
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item active
  | 
| 
551
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
552
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The B option filters stations according to the years that
  | 
| 
553
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 they were active.  If the B option is specified, but the
  | 
| 
554
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 B option is not, then B will set the B
  | 
| 
555
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 option value to the B option value so that only stations that
  | 
| 
556
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 were active during the requested data range will be selected.
  | 
| 
557
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
558
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =item quality
  | 
| 
559
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
560
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 The B option determines whether a station's data will be
  | 
| 
561
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 included in the output when it has missing data.  Quality is
  | 
| 
562
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 expressed as a number between 0 and 100, representing the percentage
  | 
| 
563
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 of data that cannot be missing; 90% is the default  For example, if
  | 
| 
564
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 you have a range of 3 years (1095 days) when B is 90, then
  | 
| 
565
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 you need 90% x 1095 = 985 days of data.  Anything less and the
  | 
| 
566
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 station is rejected.
  | 
| 
567
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
568
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 When filters fmonth and fday are used, the amount of data included
  | 
| 
569
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 will typically drop far below 90% thereby rejecting all stations.
  | 
| 
570
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 To avoid this nuisance, B will set quality to 0% if
  | 
| 
571
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 either the B or B options are present.
  | 
| 
572
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
573
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =back
  | 
| 
574
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
575
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
576
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
577
 | 
124
 | 
 
 | 
 
 | 
  
124
  
 | 
  
1
  
 | 
379
 | 
 method initialize () {
  | 
| 
 
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
214
 | 
    | 
| 
 
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
182
 | 
    | 
| 
578
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
191
 | 
     my @errors;
  | 
| 
579
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
580
 | 
124
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2152
 | 
     if ( $_opt_obj->country ) {
  | 
| 
581
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # using undef as the search type so it will figure it out based
  | 
| 
582
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # on the value pattern and length
  | 
| 
583
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
213
 | 
         my @cou = search_country( $_opt_obj->country, undef );
  | 
| 
584
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
585
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
40
 | 
         push @errors, '*E* unrecognized country code or name'
  | 
| 
586
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if not @cou;
  | 
| 
587
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
588
 | 
8
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
36
 | 
         push @errors, '*E* ambiguous country code or name'
  | 
| 
589
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if @cou > 1;
  | 
| 
590
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
591
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # return the GEC (FIPS) country code, which is what GHCN uses
  | 
| 
592
 | 
8
 | 
 
 | 
 
 | 
 
 | 
 
 | 
222
 | 
         $_opt_obj->country = $cou[0]->{gec};
  | 
| 
593
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
594
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
595
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # default the station active range to the year filter range if its value is an empty string
  | 
| 
596
 | 
124
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
4717
 | 
     if ( $_opt_obj->defined('active') and $_opt_obj->active eq $EMPTY ) {
  | 
| 
597
 | 
5
 | 
 
 | 
 
 | 
 
 | 
 
 | 
256
 | 
         $_opt_obj->active = $_opt_obj->range;
  | 
| 
598
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
599
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
600
 | 
124
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
3315
 | 
     $_opt_obj->quality = 0
  | 
| 
601
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if $_opt_obj->fmonth or $_opt_obj->fday;
  | 
| 
602
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
603
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7269
 | 
     return @errors;
  | 
| 
604
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
605
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
606
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 options_as_string
  | 
| 
607
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
608
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This option returns a string that contains all the options and their
  | 
| 
609
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 values, in a format similar to what they would look like when entered
  | 
| 
610
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 as command-line arguments.  For boolean options only the option name
  | 
| 
611
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 is include (no value).  Option values containing whitespace are
  | 
| 
612
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 enclosed in double quotes.  Option/value pairs are separated by
  | 
| 
613
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 two spaces.
  | 
| 
614
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
615
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This method is primarily provided so the consuming application can
  | 
| 
616
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 print the options that were used during a run, perhaps to a log or
  | 
| 
617
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 in the output.
  | 
| 
618
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
619
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
620
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
621
 | 
6
 | 
 
 | 
 
 | 
  
6
  
 | 
  
1
  
 | 
467
 | 
 method options_as_string () {
  | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
15
 | 
    | 
| 
 
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
    | 
| 
622
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
11
 | 
     my @options;
  | 
| 
623
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
26
 | 
     my $boolean = _get_boolean_options($Tk_opt_table);
  | 
| 
624
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
625
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
95
 | 
     foreach my $k ( sort keys $_opt_href->%* ) {
  | 
| 
626
 | 
153
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
270
 | 
         next if $k eq 'aliases';
  | 
| 
627
 | 
150
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
280
 | 
         next if $k eq 'cachedir';
  | 
| 
628
 | 
144
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
235
 | 
         next if $k eq 'profile';
  | 
| 
629
 | 
138
 | 
 
 | 
 
 | 
 
 | 
 
 | 
218
 | 
         my $v = $_opt_href->{$k};
  | 
| 
630
 | 
138
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
248
 | 
         next if not defined $v;
  | 
| 
631
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
632
 | 
49
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
98
 | 
         if ( $boolean->{$k} ) {
  | 
| 
633
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
6
 | 
             push @options, $DASH . $k;
  | 
| 
634
 | 
2
 | 
 
 | 
 
 | 
 
 | 
 
 | 
5
 | 
             next;
  | 
| 
635
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }
  | 
| 
636
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
637
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
         my $val = $v;
  | 
| 
638
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
639
 | 
47
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
141
 | 
         if ( $val =~ m{\A \s* \Z}xms ) {
  | 
| 
640
 | 
0
 | 
 
 | 
 
 | 
 
 | 
 
 | 
0
 | 
             $val = q(") . $val . q(");
  | 
| 
641
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }
  | 
| 
642
 | 
47
 | 
 
 | 
 
 | 
 
 | 
 
 | 
128
 | 
         push @options, $DASH . $k. $SPACE . $val;
  | 
| 
643
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
644
 | 
6
 | 
 
 | 
 
 | 
 
 | 
 
 | 
79
 | 
     return join $SPACE x 2, @options;
  | 
| 
645
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
646
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
647
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 validate
  | 
| 
648
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
649
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Returns:  @errors
  | 
| 
650
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
651
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 This method is called by StationTable->set_options to make sure all
  | 
| 
652
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 the options that were provided to B are valid.  It also
  | 
| 
653
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 handles abbreviations for options color and report.  Any errors
  | 
| 
654
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 arising from invalid value or from problems detected during
  | 
| 
655
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 B (which is called at the end of B) are returned
  | 
| 
656
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 in a list.
  | 
| 
657
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
658
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
659
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
660
 | 
124
 | 
 
 | 
 
 | 
  
124
  
 | 
  
1
  
 | 
4610
 | 
 method validate () {
  | 
| 
 
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
200
 | 
    | 
| 
 
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
173
 | 
    | 
| 
661
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
204
 | 
     my @errors;
  | 
| 
662
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
197
 | 
     my $bad_range_cnt = 0;
  | 
| 
663
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
664
 | 
124
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2528
 | 
     if ( $_opt_obj->defined('aliases') ) {
  | 
| 
665
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
239
 | 
         foreach my $alias_name ( keys $_opt_obj->aliases->%* ) {
  | 
| 
666
 | 
23
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1679
 | 
             my $errmsg = '*E* alias names in profile must be lowercase letters with optional underscore prefix: ' . $alias_name;
  | 
| 
667
 | 
23
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
166
 | 
             push @errors, $errmsg
  | 
| 
668
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 unless $alias_name =~ $ALIAS_NAME_RE;
  | 
| 
669
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }
  | 
| 
670
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
671
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
672
 | 
124
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2598
 | 
     if ( $_opt_obj->active ) {
  | 
| 
673
 | 
24
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
640
 | 
         if ( not $_opt_obj->active =~ m{ \A (18|19|20)\d\d [-] (18|19|20)\d\d }xms ) {
  | 
| 
674
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
183
 | 
             push @errors, '*E* invalid -active year range ' . $_opt_obj->active;
  | 
| 
675
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
             $bad_range_cnt++;
  | 
| 
676
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }
  | 
| 
677
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
678
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
679
 | 
124
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
4668
 | 
     if ( $_opt_obj->range ) {
  | 
| 
680
 | 
33
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
883
 | 
         if ( not $_opt_obj->range =~ m{ \A (18|19|20)\d\d [-,] (18|19|20)\d\d }xms ) {
  | 
| 
681
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
185
 | 
             push @errors, '*E* invalid -range ' . $_opt_obj->range;
  | 
| 
682
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
74
 | 
             $bad_range_cnt++;
  | 
| 
683
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }
  | 
| 
684
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
685
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
686
 | 
124
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
4413
 | 
     push @errors, '*E* invalid 2-character state or province code ' . $_opt_obj->state
  | 
| 
687
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if $_opt_obj->defined('state') and not $_opt_obj->state =~ m{ \A [[:alpha:]]{2} \Z }xms;
  | 
| 
688
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
689
 | 
124
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
3505
 | 
     push @errors, '*E* -partial only allowed if -active specified'
  | 
| 
690
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if $_opt_obj->partial and not $_opt_obj->defined('active');
  | 
| 
691
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
692
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # Note: full Condition Coverage in Devel::Cover seems impossible if these two ifs are combined
  | 
| 
693
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #       (I tried every combination of uncoverable branch and condition I could think of to
  | 
| 
694
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #        to suppress the missing case.  In the end, this was the only thing that worked.)
  | 
| 
695
 | 
124
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
4520
 | 
     if ( $_opt_obj->range and $_opt_obj->active ) {
  | 
| 
696
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         # uncoverable branch false
  | 
| 
697
 | 
9
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
317
 | 
         if ( $bad_range_cnt == 0 ) {
  | 
| 
698
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
135
 | 
             my $r = rng_new( $_opt_obj->range  );
  | 
| 
699
 | 
9
 | 
 
 | 
 
 | 
 
 | 
 
 | 
197
 | 
             my $a = rng_new( $_opt_obj->active );
  | 
| 
700
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
701
 | 
9
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
29
 | 
             push @errors, '*E* -range must be a subset of -active'
  | 
| 
702
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
                 if not $r->subset($a);
  | 
| 
703
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }
  | 
| 
704
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
705
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
706
 | 
124
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
7472
 | 
     push @errors, '*E* -gps argument must be decimal lat/long, separated by spaces or punctuation'
  | 
| 
707
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if $_opt_obj->gps and $_opt_obj->gps !~ m{ \A [+-]? \d{1,3} [.] \d+ (?: [[:punct:]] | \s+ ) [+-]? \d{1,3} [.] \d+ \Z }xms;
  | 
| 
708
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
709
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3176
 | 
     my %report_abbrev = abbrev( @REPORT_TYPE_LIST );
  | 
| 
710
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
711
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
28411
 | 
     my $report = lc $_opt_obj->report;
  | 
| 
712
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
713
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # uncoverable branch true
  | 
| 
714
 | 
124
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
3039
 | 
     croak '*E* undef report type'
  | 
| 
715
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if not defined $report;
  | 
| 
716
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
717
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     push @errors, '*E* invalid report option: ' . $report
  | 
| 
718
 | 
124
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
431
 | 
         if $report and not $report_abbrev{ $report };
  | 
| 
719
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
720
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2080
 | 
     $_opt_obj->report = $report_abbrev{ $report };
  | 
| 
721
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
722
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
723
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1401
 | 
     my %refresh_abbrev = abbrev( qw(yearly never always) );
  | 
| 
724
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
725
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
14754
 | 
     my $refresh = lc $_opt_obj->refresh;
  | 
| 
726
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
727
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # uncoverable branch true
  | 
| 
728
 | 
124
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
1948
 | 
     croak '*E* undef refresh option'
  | 
| 
729
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         if not defined $refresh;
  | 
| 
730
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
731
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     push @errors, '*E* invalid refresh option: ' . $refresh
  | 
| 
732
 | 
124
 | 
  
 50
  
 | 
  
 33
  
 | 
 
 | 
 
 | 
601
 | 
         if $refresh and not $refresh_abbrev{ $refresh };
  | 
| 
733
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
734
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2041
 | 
     $_opt_obj->refresh = $refresh_abbrev{ $refresh };
  | 
| 
735
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
736
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #-----------------------------------------------------------------
  | 
| 
737
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # end of noted section
  | 
| 
738
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     #-----------------------------------------------------------------
  | 
| 
739
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
740
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1374
 | 
     my %color_abbrev = abbrev( qw(blue green azure purple red white yellow) );
  | 
| 
741
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
742
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     # uncoverable branch false
  | 
| 
743
 | 
124
 | 
  
 50
  
 | 
 
 | 
 
 | 
 
 | 
24687
 | 
     if ( $_opt_obj->defined('kmlcolor') ) {
  | 
| 
744
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
2577
 | 
         my $kmlcolor = $_opt_obj->kmlcolor;
  | 
| 
745
 | 
124
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2912
 | 
         if ( $kmlcolor eq $EMPTY ) {
  | 
| 
746
 | 
1
 | 
 
 | 
 
 | 
 
 | 
 
 | 
3
 | 
             push @errors, '*E* invalid -kmlcolor value ""'
  | 
| 
747
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         } else {
  | 
| 
748
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             push @errors, '*E* invalid -kmlcolor value'
  | 
| 
749
 | 
123
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
331
 | 
                 if not $color_abbrev{ $kmlcolor };
  | 
| 
750
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
         }
  | 
| 
751
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1941
 | 
         $_opt_obj->kmlcolor = $color_abbrev{ $kmlcolor };
  | 
| 
752
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
753
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
754
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
755
 | 
124
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
2954
 | 
     if ( $_opt_obj->defined('fmonth') ) {
  | 
| 
756
 | 
15
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
355
 | 
         push @errors, '*E* -fmonth must be a single number or valid range spec (e.g. 1-5,9)'
  | 
| 
757
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if not rng_valid($_opt_obj->fmonth)
  | 
| 
758
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             or not rng_within($_opt_obj->fmonth, '1-12');
  | 
| 
759
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
760
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
761
 | 
124
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
9041
 | 
     if ( $_opt_obj->defined('fday') ) {
  | 
| 
762
 | 
15
 | 
  
100
  
 | 
  
100
  
 | 
 
 | 
 
 | 
321
 | 
         push @errors, '*E* -fday must be a single number or valid range spec (e.g. 3,15,20-31)'
  | 
| 
763
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             if not rng_valid($_opt_obj->fday)
  | 
| 
764
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
             or not rng_within($_opt_obj->fday, '1-31');
  | 
| 
765
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
766
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
767
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
7204
 | 
     my @init_errors = $self->initialize();
  | 
| 
768
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
769
 | 
124
 | 
 
 | 
 
 | 
 
 | 
 
 | 
1869
 | 
     return (@errors, @init_errors);
  | 
| 
770
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
771
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
772
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 DOES
  | 
| 
773
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
774
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Defined by Object::Pad.  Included for POD::Coverage.
  | 
| 
775
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
776
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =head2 META
  | 
| 
777
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
778
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 Defined by Object::Pad.  Included for POD::Coverage.
  | 
| 
779
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
780
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 =cut
  | 
| 
781
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
782
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ######################################################################
  | 
| 
783
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 # Subroutines
  | 
| 
784
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 ######################################################################
  | 
| 
785
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
786
 | 
7
 | 
 
 | 
 
 | 
  
7
  
 | 
 
 | 
17
 | 
 sub _get_boolean_options ($_tk_opt_aref) {
  | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
13
 | 
    | 
| 
 
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
16
 | 
    | 
| 
787
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
788
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
12
 | 
     my %boolean;
  | 
| 
789
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
790
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
23
 | 
     foreach my $row ( $_tk_opt_aref->@* ) {
  | 
| 
791
 | 
231
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
435
 | 
         next unless ref $row eq 'ARRAY';
  | 
| 
792
 | 
196
 | 
 
 | 
 
 | 
 
 | 
 
 | 
467
 | 
         my ($name, $type) = $row->@*;
  | 
| 
793
 | 
196
 | 
  
100
  
 | 
 
 | 
 
 | 
 
 | 
462
 | 
         $boolean{$name}++ if $type eq $BANG;
  | 
| 
794
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
     }
  | 
| 
795
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
796
 | 
7
 | 
 
 | 
 
 | 
 
 | 
 
 | 
29
 | 
     return \%boolean;
  | 
| 
797
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 }
  | 
| 
798
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
  | 
| 
799
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 
 | 
 1;  |