line  
 stmt  
 bran  
 cond  
 sub  
 pod  
 time  
 code  
 
1 
 
  
 
   
 
 
 
 
 
 
 
 
 
 
 
 package Wiki::Toolkit::Feed::Atom;  
 
2 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
3 
 
3
 
 
 
 
 
  
3
   
 
 
 
2397
 
 use strict;  
 
  
 
3
 
 
 
 
 
 
 
 
 
8
 
    
 
  
 
3
 
 
 
 
 
 
 
 
 
283
 
    
 
4 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
5 
 
3
 
 
 
 
 
  
3
   
 
 
 
17
 
 use vars qw( @ISA $VERSION );  
 
  
 
3
 
 
 
 
 
 
 
 
 
6
 
    
 
  
 
3
 
 
 
 
 
 
 
 
 
183
 
    
 
6 
 
 
 
 
 
 
 
 
 
 
 
 
 
 $VERSION = '0.03';  
 
7 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
8 
 
3
 
 
 
 
 
  
3
   
 
 
 
1493
 
 use POSIX 'strftime';  
 
  
 
3
 
 
 
 
 
 
 
 
 
18554
 
    
 
  
 
3
 
 
 
 
 
 
 
 
 
17
 
    
 
9 
 
3
 
 
 
 
 
  
3
   
 
 
 
5742
 
 use Time::Piece;  
 
  
 
3
 
 
 
 
 
 
 
 
 
29733
 
    
 
  
 
3
 
 
 
 
 
 
 
 
 
15
 
    
 
10 
 
3
 
 
 
 
 
  
3
   
 
 
 
226
 
 use URI::Escape;  
 
  
 
3
 
 
 
 
 
 
 
 
 
7
 
    
 
  
 
3
 
 
 
 
 
 
 
 
 
177
 
    
 
11 
 
3
 
 
 
 
 
  
3
   
 
 
 
19
 
 use Carp qw( croak );  
 
  
 
3
 
 
 
 
 
 
 
 
 
7
 
    
 
  
 
3
 
 
 
 
 
 
 
 
 
124
 
    
 
12 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
13 
 
3
 
 
 
 
 
  
3
   
 
 
 
1520
 
 use Wiki::Toolkit::Feed::Listing;  
 
  
 
3
 
 
 
 
 
 
 
 
 
9
 
    
 
  
 
3
 
 
 
 
 
 
 
 
 
4260
 
    
 
14 
 
 
 
 
 
 
 
 
 
 
 
 
 
 @ISA = qw( Wiki::Toolkit::Feed::Listing );  
 
15 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
16 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 NAME  
 
17 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
18 
 
 
 
 
 
 
 
 
 
 
 
 
 
   Wiki::Toolkit::Feed::Atom - A Wiki::Toolkit plugin to output RecentChanges Atom.  
 
19 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
20 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 DESCRIPTION  
 
21 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
22 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This is an alternative access to the recent changes of a Wiki::Toolkit  
 
23 
 
 
 
 
 
 
 
 
 
 
 
 
 
 wiki. It outputs the Atom Syndication Format as described at  
 
24 
 
 
 
 
 
 
 
 
 
 
 
 
 
 L 
 
25 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
26 
 
 
 
 
 
 
 
 
 
 
 
 
 
 This module is a straight port of L.   
 
27 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
28 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 SYNOPSIS  
 
29 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
30 
 
 
 
 
 
 
 
 
 
 
 
 
 
   use Wiki::Toolkit;  
 
31 
 
 
 
 
 
 
 
 
 
 
 
 
 
   use Wiki::Toolkit::Feed::Atom;  
 
32 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
33 
 
 
 
 
 
 
 
 
 
 
 
 
 
   my $wiki = Wiki::Toolkit->new( ... );  # See perldoc Wiki::Toolkit  
 
34 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
35 
 
 
 
 
 
 
 
 
 
 
 
 
 
   # Set up the RSS feeder with the mandatory arguments - see  
 
36 
 
 
 
 
 
 
 
 
 
 
 
 
 
   # C below for more, optional, arguments.   
 
37 
 
 
 
 
 
 
 
 
 
 
 
 
 
   my $atom = Wiki::Toolkit::Feed::Atom->new(  
 
38 
 
 
 
 
 
 
 
 
 
 
 
 
 
     wiki                => $wiki,  
 
39 
 
 
 
 
 
 
 
 
 
 
 
 
 
     site_name           => 'My Wiki',  
 
40 
 
 
 
 
 
 
 
 
 
 
 
 
 
     site_url            => 'http://example.com/',  
 
41 
 
 
 
 
 
 
 
 
 
 
 
 
 
     make_node_url       => sub  
 
42 
 
 
 
 
 
 
 
 
 
 
 
 
 
                            {  
 
43 
 
 
 
 
 
 
 
 
 
 
 
 
 
                              my ($node_name, $version) = @_;  
 
44 
 
 
 
 
 
 
 
 
 
 
 
 
 
                              return 'http://example.com/?id=' . uri_escape($node_name) . ';version=' . uri_escape($version);  
 
45 
 
 
 
 
 
 
 
 
 
 
 
 
 
                            },  
 
46 
 
 
 
 
 
 
 
 
 
 
 
 
 
     html_equiv_link => 'http://example.com/?RecentChanges',  
 
47 
 
 
 
 
 
 
 
 
 
 
 
 
 
     atom_link => 'http://example.com/?action=rc;format=atom',  
 
48 
 
 
 
 
 
 
 
 
 
 
 
 
 
   );  
 
49 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
50 
 
 
 
 
 
 
 
 
 
 
 
 
 
   print "Content-type: application/atom+xml\n\n";  
 
51 
 
 
 
 
 
 
 
 
 
 
 
 
 
   print $atom->recent_changes;  
 
52 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
53 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head1 METHODS  
 
54 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
55 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 C   
 
56 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
57 
 
 
 
 
 
 
 
 
 
 
 
 
 
   my $atom = Wiki::Toolkit::Feed::Atom->new(  
 
58 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # Mandatory arguments:  
 
59 
 
 
 
 
 
 
 
 
 
 
 
 
 
     wiki                 => $wiki,  
 
60 
 
 
 
 
 
 
 
 
 
 
 
 
 
     site_name            => 'My Wiki',  
 
61 
 
 
 
 
 
 
 
 
 
 
 
 
 
     site_url             => 'http://example.com/',  
 
62 
 
 
 
 
 
 
 
 
 
 
 
 
 
     make_node_url        => sub  
 
63 
 
 
 
 
 
 
 
 
 
 
 
 
 
                             {  
 
64 
 
 
 
 
 
 
 
 
 
 
 
 
 
                               my ($node_name, $version) = @_;  
 
65 
 
 
 
 
 
 
 
 
 
 
 
 
 
                               return 'http://example.com/?id=' . uri_escape($node_name) . ';version=' . uri_escape($version);  
 
66 
 
 
 
 
 
 
 
 
 
 
 
 
 
                             },  
 
67 
 
 
 
 
 
 
 
 
 
 
 
 
 
     html_equiv_link  => 'http://example.com/?RecentChanges',,  
 
68 
 
 
 
 
 
 
 
 
 
 
 
 
 
     atom_link => 'http://example.com/?action=rc;format=atom',  
 
69 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
70 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # Optional arguments:  
 
71 
 
 
 
 
 
 
 
 
 
 
 
 
 
     site_description     => 'My wiki about my stuff',  
 
72 
 
 
 
 
 
 
 
 
 
 
 
 
 
     software_name        => $your_software_name,     # e.g. "Wiki::Toolkit"  
 
73 
 
 
 
 
 
 
 
 
 
 
 
 
 
     software_version     => $your_software_version,  # e.g. "0.73"  
 
74 
 
 
 
 
 
 
 
 
 
 
 
 
 
     software_homepage    => $your_software_homepage, # e.g. "http://search.cpan.org/dist/CGI-Wiki/"  
 
75 
 
 
 
 
 
 
 
 
 
 
 
 
 
     encoding             => 'UTF-8'  
 
76 
 
 
 
 
 
 
 
 
 
 
 
 
 
   );  
 
77 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
78 
 
 
 
 
 
 
 
 
 
 
 
 
 
 C must be a L object. C, if supplied, must      
 
79 
 
 
 
 
 
 
 
 
 
 
 
 
 
 be a coderef.  
 
80 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
81 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The mandatory arguments are:  
 
82 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
83 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =over 4  
 
84 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
85 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item * wiki  
 
86 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
87 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item * site_name  
 
88 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
89 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item * site_url  
 
90 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
91 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item * make_node_url  
 
92 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
93 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item * html_equiv_link or recent_changes_link  
 
94 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
95 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item * atom_link  
 
96 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
97 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =back  
 
98 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
99 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The three optional arguments  
 
100 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
101 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =over 4  
 
102 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
103 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item * software_name  
 
104 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
105 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item * software_version  
 
106 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
107 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item * software_homepage  
 
108 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
109 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =back  
 
110 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
111 
 
 
 
 
 
 
 
 
 
 
 
 
 
 are used to generate the C part of the feed.   
 
112 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
113 
 
 
 
 
 
 
 
 
 
 
 
 
 
 The optional argument  
 
114 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
115 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =over 4  
 
116 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
117 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item * encoding  
 
118 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
119 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =back  
 
120 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
121 
 
 
 
 
 
 
 
 
 
 
 
 
 
 will be used to specify the character encoding in the feed. If not set,  
 
122 
 
 
 
 
 
 
 
 
 
 
 
 
 
 will default to the wiki store's encoding.  
 
123 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
124 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 C   
 
125 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
126 
 
 
 
 
 
 
 
 
 
 
 
 
 
   $wiki->write_node(  
 
127 
 
 
 
 
 
 
 
 
 
 
 
 
 
                      'About This Wiki',  
 
128 
 
 
 
 
 
 
 
 
 
 
 
 
 
                      'blah blah blah',  
 
129 
 
 
 
 
 
 
 
 
 
 
 
 
 
                          $checksum,  
 
130 
 
 
 
 
 
 
 
 
 
 
 
 
 
                          {  
 
131 
 
 
 
 
 
 
 
 
 
 
 
 
 
                            comment  => 'Stub page, please update!',  
 
132 
 
 
 
 
 
 
 
 
 
 
 
 
 
                            username => 'Fred',  
 
133 
 
 
 
 
 
 
 
 
 
 
 
 
 
                          }  
 
134 
 
 
 
 
 
 
 
 
 
 
 
 
 
   );  
 
135 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
136 
 
 
 
 
 
 
 
 
 
 
 
 
 
   print "Content-type: application/atom+xml\n\n";  
 
137 
 
 
 
 
 
 
 
 
 
 
 
 
 
   print $atom->recent_changes;  
 
138 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
139 
 
 
 
 
 
 
 
 
 
 
 
 
 
   # Or get something other than the default of the latest 15 changes.  
 
140 
 
 
 
 
 
 
 
 
 
 
 
 
 
   print $atom->recent_changes( items => 50 );  
 
141 
 
 
 
 
 
 
 
 
 
 
 
 
 
   print $atom->recent_changes( days => 7 );  
 
142 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
143 
 
 
 
 
 
 
 
 
 
 
 
 
 
   # Or ignore minor edits.  
 
144 
 
 
 
 
 
 
 
 
 
 
 
 
 
   print $atom->recent_changes( ignore_minor_edits => 1 );  
 
145 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
146 
 
 
 
 
 
 
 
 
 
 
 
 
 
   # Personalise your feed further - consider only changes  
 
147 
 
 
 
 
 
 
 
 
 
 
 
 
 
   # made by Fred to pages about bookshops.  
 
148 
 
 
 
 
 
 
 
 
 
 
 
 
 
   print $atom->recent_changes(  
 
149 
 
 
 
 
 
 
 
 
 
 
 
 
 
              filter_on_metadata => {  
 
150 
 
 
 
 
 
 
 
 
 
 
 
 
 
                          username => 'Fred',  
 
151 
 
 
 
 
 
 
 
 
 
 
 
 
 
                          category => 'Bookshops',  
 
152 
 
 
 
 
 
 
 
 
 
 
 
 
 
                        },  
 
153 
 
 
 
 
 
 
 
 
 
 
 
 
 
               );  
 
154 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
155 
 
 
 
 
 
 
 
 
 
 
 
 
 
 If using C, note that only changes satisfying   
 
156 
 
 
 
 
 
 
 
 
 
 
 
 
 
 I criteria will be returned.   
 
157 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
158 
 
 
 
 
 
 
 
 
 
 
 
 
 
 B Many of the fields emitted by the Atom generator are taken   
 
159 
 
 
 
 
 
 
 
 
 
 
 
 
 
 from the node metadata. The form of this metadata is I mandated   
 
160 
 
 
 
 
 
 
 
 
 
 
 
 
 
 by L. Your wiki application should make sure to store some or   
 
161 
 
 
 
 
 
 
 
 
 
 
 
 
 
 all of the following metadata when calling C:   
 
162 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
163 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =over 4  
 
164 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
165 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item B - a brief comment summarising the edit that has just been made; will be used in the summary for this item.  Defaults to the empty string.   
 
166 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
167 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item B - an identifier for the person who made the edit; will be used as the Dublin Core contributor for this item, and also in the RDF description.  Defaults to 'No description given for change'.   
 
168 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
169 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =item B - the hostname or IP address of the computer used to make the edit; if no username is supplied then this will be used as the author for this item.  Defaults to 'Anonymous'.   
 
170 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
171 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =back  
 
172 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
173 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
174 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
175 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub new {  
 
176 
 
6
 
 
 
 
 
  
6
   
 
  
1
   
 
2982
 
     my $class = shift;  
 
177 
 
6
 
 
 
 
 
 
 
 
 
13
 
     my $self  = {};  
 
178 
 
6
 
 
 
 
 
 
 
 
 
14
 
     bless $self, $class;  
 
179 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
180 
 
6
 
 
 
 
 
 
 
 
 
13
 
     my %args = @_;  
 
181 
 
6
 
 
 
 
 
 
 
 
 
13
 
     my $wiki = $args{wiki};  
 
182 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
183 
 
6
 
  
 50
   
 
  
 66
   
 
 
 
 
 
44
 
     unless ($wiki && UNIVERSAL::isa($wiki, 'Wiki::Toolkit')) {  
 
184 
 
6
 
 
 
 
 
 
 
 
 
935
 
         croak 'No Wiki::Toolkit object supplied';  
 
185 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
186 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
187 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     $self->{wiki} = $wiki;  
 
188 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
189 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # Mandatory arguments.  
 
190 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     foreach my $arg (qw/site_name site_url make_node_url atom_link/) {  
 
191 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
         croak "No $arg supplied" unless $args{$arg};  
 
192 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $self->{$arg} = $args{$arg};  
 
193 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
194 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
195 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # Must-supply-one-of arguments  
 
196 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     my %mustoneof = ( 'html_equiv_link' => ['html_equiv_link','recent_changes_link'] );  
 
197 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     $self->handle_supply_one_of(\%mustoneof,\%args);  
 
198 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
199 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # Optional arguments.  
 
200 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     foreach my $arg (qw/site_description software_name software_version software_homepage encoding/) {  
 
201 
 
  
0
   
 
 
 
  
  0
   
 
 
 
 
 
 
 
         $self->{$arg} = $args{$arg} || '';  
 
202 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
203 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
204 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # Supply some defaults, if a blank string isn't what we want  
 
205 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
     unless($self->{encoding}) {  
 
206 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $self->{encoding} = $self->{wiki}->store->{_charset};  
 
207 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
208 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
209 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     $self->{timestamp_fmt} = $Wiki::Toolkit::Store::Database::timestamp_fmt;  
 
210 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     $self->{utc_offset} = strftime "%z", localtime;  
 
211 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     $self->{utc_offset} =~ s/(..)(..)$/$1:$2/;  
 
212 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
213 
 
 
 
 
 
 
 
 
 
 
 
 
 
     # Escape any &'s in the urls  
 
214 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     foreach my $key (qw(site_url atom_link)) {  
 
215 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my @ands = ($self->{$key} =~ /(\&.{1,6})/g);  
 
216 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         foreach my $and (@ands) {  
 
217 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
             if($and ne "&") {  
 
218 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
                 my $new_and = $and;  
 
219 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
                 $new_and =~ s/\&/\&/;  
 
220 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
                 $self->{$key} =~ s/$and/$new_and/;  
 
221 
 
 
 
 
 
 
 
 
 
 
 
 
 
             }  
 
222 
 
 
 
 
 
 
 
 
 
 
 
 
 
         }  
 
223 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
224 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
225 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     $self;  
 
226 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
227 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
228 
 
 
 
 
 
 
 
 
 
 
 
 
 
 # Internal method, to build all the stuff that will go at the start of a feed.  
 
229 
 
 
 
 
 
 
 
 
 
 
 
 
 
 # Outputs the feed header, and initial feed info.  
 
230 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
231 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub build_feed_start {  
 
232 
 
  
0
   
 
 
 
 
 
  
0
   
 
  
0
   
 
 
 
     my ($self,$atom_timestamp) = @_;  
 
233 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
234 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     my $generator = '';  
 
235 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
236 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
     if ($self->{software_name}) {  
 
237 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $generator  = '  
   
238 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
         $generator .= ' uri="' . $self->{software_homepage} . '"'   if $self->{software_homepage};  
 
239 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
         $generator .= ' version=' . $self->{software_version} . '"' if $self->{software_version};  
 
240 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $generator .= ">\n";  
 
241 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $generator .= $self->{software_name} . "\n";  
 
242 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }                            
 
243 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
244 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $subtitle = $self->{site_description}  
 
245 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
                  ? '' . $self->{site_description} . " \n"  
 
246 
 
 
 
 
 
 
 
 
 
 
 
 
 
                  : '';  
 
247 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
248 
 
  
0
   
 
 
 
  
  0
   
 
 
 
 
 
 
 
     $atom_timestamp ||= '';  
 
249 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
250 
 
 
 
 
 
 
 
 
 
 
 
 
 
     my $atom = qq{{encoding} . qq{"?>  
 
251 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
252 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
   
253 
 
 
 
 
 
 
 
 
 
 
 
 
 
  xmlns         = "http://www.w3.org/2005/Atom"  
 
254 
 
 
 
 
 
 
 
 
 
 
 
 
 
  xmlns:geo     = "http://www.w3.org/2003/01/geo/wgs84_pos#"  
 
255 
 
 
 
 
 
 
 
 
 
 
 
 
 
  xmlns:space   = "http://frot.org/space/0.1/"  
 
256 
 
 
 
 
 
 
 
 
 
 
 
 
 
 >  
 
257 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
258 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
259 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }                 . $self->{site_name}    . qq{   
 
260 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
261 
 
 
 
 
 
 
 
 
 
 
 
 
 
   }               . $atom_timestamp       . qq{   
 
262 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
   }                    . $self->{site_url}     . qq{   
 
263 
 
 
 
 
 
 
 
 
 
 
 
 
 
   $subtitle};  
 
264 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
265 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     return $atom;  
 
266 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
267 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
268 
 
 
 
 
 
 
 
 
 
 
 
 
 
 # Internal method, to build all the stuff that will go at the end of a feed.  
 
269 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
270 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub build_feed_end {  
 
271 
 
  
0
   
 
 
 
 
 
  
0
   
 
  
0
   
 
 
 
     my ($self,$feed_timestamp) = @_;  
 
272 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
273 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     return "\n";  
 
274 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
275 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
276 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 C   
 
277 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
278 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Generate and return an Atom feed for a list of nodes  
 
279 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
280 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
281 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
282 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub generate_node_list_feed {  
 
283 
 
  
0
   
 
 
 
 
 
  
0
   
 
  
1
   
 
 
 
     my ($self,$atom_timestamp,@nodes) = @_;  
 
284 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
285 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     my $atom = $self->build_feed_start($atom_timestamp);  
 
286 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
287 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     my (@urls, @items);  
 
288 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
289 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     foreach my $node (@nodes) {  
 
290 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $node_name = $node->{name};  
 
291 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
292 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $item_timestamp = $node->{last_modified};  
 
293 
 
 
 
 
 
 
 
 
 
 
 
 
 
       
 
294 
 
 
 
 
 
 
 
 
 
 
 
 
 
         # Make a Time::Piece object.  
 
295 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $time = Time::Piece->strptime($item_timestamp, $self->{timestamp_fmt});  
 
296 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
297 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $utc_offset = $self->{utc_offset};  
 
298 
 
 
 
 
 
 
 
 
 
 
 
 
 
       
 
299 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $item_timestamp = $time->strftime( "%Y-%m-%dT%H:%M:%S$utc_offset" );  
 
300 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
301 
 
  
0
   
 
 
 
  
  0
   
 
 
 
 
 
 
 
         my $author      = $node->{metadata}{username}[0] || $node->{metadata}{host}[0] || 'Anonymous';  
 
302 
 
  
0
   
 
 
 
  
  0
   
 
 
 
 
 
 
 
         my $description = $node->{metadata}{comment}[0]  || 'No description given for node';  
 
303 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
304 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
         $description .= " [$author]" if $author;  
 
305 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
306 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $version = $node->{version};  
 
307 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
         my $status  = (1 == $version) ? 'new' : 'updated';  
 
308 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
309 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $major_change = $node->{metadata}{major_change}[0];  
 
310 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
         $major_change = 1 unless defined $major_change;  
 
311 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
         my $importance = $major_change ? 'major' : 'minor';  
 
312 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
313 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $url = $self->{make_node_url}->($node_name, $version);  
 
314 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
315 
 
 
 
 
 
 
 
 
 
 
 
 
 
         # make XML-clean  
 
316 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $title =  $node_name;  
 
317 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $title =~ s/&/&/g;  
 
318 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $title =~ s/</g;  
 
319 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $title =~ s/>/>/g;  
 
320 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
321 
 
 
 
 
 
 
 
 
 
 
 
 
 
         # Pop the categories into atom:category elements (4.2.2)  
 
322 
 
 
 
 
 
 
 
 
 
 
 
 
 
         # We can do this because the spec says:  
 
323 
 
 
 
 
 
 
 
 
 
 
 
 
 
         #   "This specification assigns no meaning to the content (if any)   
 
324 
 
 
 
 
 
 
 
 
 
 
 
 
 
         #    of this element."  
 
325 
 
 
 
 
 
 
 
 
 
 
 
 
 
         # TODO: Decide if we should include the "all categories listing" url  
 
326 
 
 
 
 
 
 
 
 
 
 
 
 
 
         #        as the scheme (URI) attribute?  
 
327 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $category_atom = "";  
 
328 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
         if ($node->{metadata}->{category}) {  
 
329 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
             foreach my $cat (@{ $node->{metadata}->{category} }) {  
 
  
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
    
 
330 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
                 $category_atom .= "     
 
331 
 
 
 
 
 
 
 
 
 
 
 
 
 
             }  
 
332 
 
 
 
 
 
 
 
 
 
 
 
 
 
         }  
 
333 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
334 
 
 
 
 
 
 
 
 
 
 
 
 
 
         # Include geospacial data, if we have it  
 
335 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $geo_atom = $self->format_geo($node->{metadata});  
 
336 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
337 
 
 
 
 
 
 
 
 
 
 
 
 
 
         # TODO: Find an Atom equivalent of ModWiki, so we can include more info  
 
338 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
339 
 
 
 
 
 
 
 
 
 
 
 
 
 
       
 
340 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         push @items, qq{  
 
341 
 
 
 
 
 
 
 
 
 
 
 
 
 
      
 
342 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $title   
 
343 
 
 
 
 
 
 
 
 
 
 
 
 
 
      
 
344 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $url   
 
345 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $description   
 
346 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $item_timestamp   
 
347 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $author  
 
348 
 
 
 
 
 
 
 
 
 
 
 
 
 
 $category_atom  
 
349 
 
 
 
 
 
 
 
 
 
 
 
 
 
 $geo_atom  
 
350 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
351 
 
 
 
 
 
 
 
 
 
 
 
 
 
 };  
 
352 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
353 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
354 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
355 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     $atom .= join('', @items) . "\n";  
 
356 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     $atom .= $self->build_feed_end($atom_timestamp);  
 
357 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
358 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     return $atom;     
 
359 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
360 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
361 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 C   
 
362 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
363 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Generate a very cut down atom feed, based just on the nodes, their locations  
 
364 
 
 
 
 
 
 
 
 
 
 
 
 
 
 (if given), and their distance from a reference location (if given).  
 
365 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
366 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Typically used on search feeds.  
 
367 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
368 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
369 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
370 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub generate_node_name_distance_feed {  
 
371 
 
  
0
   
 
 
 
 
 
  
0
   
 
  
1
   
 
 
 
     my ($self,$atom_timestamp,@nodes) = @_;  
 
372 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
373 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     my $atom = $self->build_feed_start($atom_timestamp);  
 
374 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
375 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     my (@urls, @items);  
 
376 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
377 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     foreach my $node (@nodes) {  
 
378 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $node_name = $node->{name};  
 
379 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
380 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $url = $self->{make_node_url}->($node_name);  
 
381 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
382 
 
 
 
 
 
 
 
 
 
 
 
 
 
         # make XML-clean  
 
383 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $title =  $node_name;  
 
384 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $title =~ s/&/&/g;  
 
385 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $title =~ s/</g;  
 
386 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $title =~ s/>/>/g;  
 
387 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
388 
 
 
 
 
 
 
 
 
 
 
 
 
 
         # What location stuff do we have?  
 
389 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         my $geo_atom = $self->format_geo($node);  
 
390 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
391 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         push @items, qq{  
 
392 
 
 
 
 
 
 
 
 
 
 
 
 
 
      
 
393 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $title   
 
394 
 
 
 
 
 
 
 
 
 
 
 
 
 
      
 
395 
 
 
 
 
 
 
 
 
 
 
 
 
 
     $url   
 
396 
 
 
 
 
 
 
 
 
 
 
 
 
 
 $geo_atom  
 
397 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
398 
 
 
 
 
 
 
 
 
 
 
 
 
 
 };  
 
399 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
400 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
401 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
402 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     $atom .= join('', @items) . "\n";  
 
403 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     $atom .= $self->build_feed_end($atom_timestamp);  
 
404 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
405 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     return $atom;     
 
406 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
407 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
408 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 C   
 
409 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
410 
 
 
 
 
 
 
 
 
 
 
 
 
 
   print $atom->feed_timestamp();  
 
411 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
412 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Returns the timestamp of the feed in POSIX::strftime style ("Tue, 29 Feb 2000   
 
413 
 
 
 
 
 
 
 
 
 
 
 
 
 
 12:34:56 GMT"), which is equivalent to the timestamp of the most recent item   
 
414 
 
 
 
 
 
 
 
 
 
 
 
 
 
 in the feed. Takes the same arguments as recent_changes(). You will most likely  
 
415 
 
 
 
 
 
 
 
 
 
 
 
 
 
 need this to print a Last-Modified HTTP header so user-agents can determine  
 
416 
 
 
 
 
 
 
 
 
 
 
 
 
 
 whether they need to reload the feed or not.  
 
417 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
418 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
419 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
420 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub feed_timestamp {  
 
421 
 
  
0
   
 
 
 
 
 
  
0
   
 
  
1
   
 
 
 
     my ($self, $newest_node) = @_;  
 
422 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
423 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     my $time;  
 
424 
 
  
0
   
 
  
  0
   
 
 
 
 
 
 
 
 
 
     if ($newest_node->{last_modified}) {  
 
425 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $time = Time::Piece->strptime( $newest_node->{last_modified}, $self->{timestamp_fmt} );  
 
426 
 
 
 
 
 
 
 
 
 
 
 
 
 
     } else {  
 
427 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
         $time = localtime;  
 
428 
 
 
 
 
 
 
 
 
 
 
 
 
 
     }  
 
429 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
430 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     my $utc_offset = $self->{utc_offset};  
 
431 
 
 
 
 
 
 
 
 
 
 
 
 
 
       
 
432 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     return $time->strftime( "%Y-%m-%dT%H:%M:%S$utc_offset" );  
 
433 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
434 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
435 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
436 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =head2 C   
 
437 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
438 
 
 
 
 
 
 
 
 
 
 
 
 
 
 Take a feed_timestamp and return a Time::Piece object.   
 
439 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
440 
 
 
 
 
 
 
 
 
 
 
 
 
 
 =cut  
 
441 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
442 
 
 
 
 
 
 
 
 
 
 
 
 
 
 sub parse_feed_timestamp {  
 
443 
 
  
0
   
 
 
 
 
 
  
0
   
 
  
1
   
 
 
 
     my ($self, $feed_timestamp) = @_;  
 
444 
 
 
 
 
 
 
 
 
 
 
 
 
 
      
 
445 
 
  
0
   
 
 
 
 
 
 
 
 
 
 
 
     $feed_timestamp = substr($feed_timestamp, 0, -length( $self->{utc_offset}));  
 
446 
 
0
 
 
 
 
 
 
 
 
 
 
 
     return Time::Piece->strptime( $feed_timestamp, '%Y-%m-%dT%H:%M:%S' );  
 
447 
 
 
 
 
 
 
 
 
 
 
 
 
 
 }  
 
448 
 
 
 
 
 
 
 
 
 
 
 
 
 
 1;  
 
449 
 
 
 
 
 
 
 
 
 
 
 
 
 
    
 
450 
 
 
 
 
 
 
 
 
 
 
 
 
 
 __END__