Browse code

Add a perl script that automatically queries http, https, and ftp for their date of last update. This also includes much more metadata about each mirror. It isn't ready to be used, the main mirror page needs to be updated to incorporate the new fields that are often blank.

Jacob Appelbaum authored on27/06/2008 12:35:38
Showing1 changed files
1 1
new file mode 100755
... ...
@@ -0,0 +1,646 @@
1
+#!/usr/bin/perl -w
2
+use warnings;
3
+use strict;
4
+use LWP::Simple;
5
+use LWP;
6
+use Date::Parse;
7
+
8
+print "Creating LWP agent ($LWP::VERSION)...\n";
9
+my $lua = LWP::UserAgent->new(
10
+    keep_alive => 1,
11
+    timeout => 15, 
12
+    agent => "Tor MirrorCheck Agent"
13
+);
14
+
15
+sub sanitize {
16
+    my $taintedData = shift;
17
+    my $cleanedData;
18
+    my $whitelist = '-a-zA-Z0-9: +';
19
+
20
+    # clean the data, return cleaned data
21
+    $taintedData =~ s/[^$whitelist]//go;
22
+    $cleanedData = $taintedData;
23
+
24
+    return $cleanedData;
25
+}
26
+
27
+sub FetchDate {
28
+    my $url = shift; # Base url for mirror
29
+    my $trace = "project/trace/www.torproject.org"; # Location of recent update info
30
+    $url = "$url$trace";
31
+
32
+    print "Fetching possible date from: $url\n";
33
+
34
+    my $request = new HTTP::Request GET => "$url";
35
+    my $result = $lua->request($request);
36
+
37
+    if ($result->is_success){
38
+       my $taint = $result->content;
39
+       my $content = sanitize($taint);
40
+       if ($content) {
41
+            
42
+            my $date = str2time($content);
43
+
44
+            if ($date) {
45
+                print "We've fetched a date $date.\n";
46
+                return $date;
47
+            } else {
48
+                print "We've haven't fetched a date.\n";
49
+                return "Unknown";
50
+            }
51
+
52
+        } else {
53
+            print "Unable to fetch date, empty content returned.\n";
54
+            return "Unknown";
55
+        }
56
+            
57
+    } else {
58
+       print "Our request failed, we had no result.\n";
59
+       return "Unknown";
60
+    }
61
+}
62
+
63
+# This is the list of all known Tor mirrors
64
+# Add new mirrors to the bottom!
65
+my %m = ( 
66
+       mirror000 => {
67
+            orgName => "cypherpunks.at",
68
+            isoCC => "AT",
69
+            subRegion => "",
70
+            region => "Europe",
71
+            ipv4 => "True",
72
+            ipv6 => "False",
73
+            loadBalanced => "Unknown",
74
+            httpWebsiteMirror => "http://tor.cypherpunks.at/",
75
+            rsyncWebsiteMirror => "rsync://tor.cypherpunks.at/tor",
76
+            httpDistMirror => "http://tor.cypherpunks.at/dist/",
77
+            rsyncDistMirror => "rsync: tor.cypherpunks.at::tor/dist/",
78
+            updateDate => "",
79
+        },
80
+
81
+       mirror001 => {
82
+            orgName => "depthstrike.com",
83
+            isoCC => "CA",
84
+            subRegion => "NS",
85
+            region => "North America",
86
+            ipv4 => "True",
87
+            ipv6 => "False",
88
+            loadBalanced => "Unknown",
89
+            httpWebsiteMirror => "http://tor.depthstrike.com/",
90
+            ftpWebsiteMirror => "",
91
+            rsyncWebsiteMirror => "",
92
+            httpDistMirror => "http://tor.depthstrike.com/dist/",
93
+            rsyncDistMirror => "",
94
+            updateDate => "",
95
+        },
96
+
97
+       mirror001 => {
98
+            orgName => "depthstrike.com",
99
+            isoCC => "CA",
100
+            subRegion => "NS",
101
+            region => "North America",
102
+            ipv4 => "True",
103
+            ipv6 => "False",
104
+            loadBalanced => "Unknown",
105
+            httpWebsiteMirror => "http://tor.depthstrike.com/",
106
+            ftpWebsiteMirror => "",
107
+            rsyncWebsiteMirror => "",
108
+            httpDistMirror => "http://tor.depthstrike.com/dist/",
109
+            rsyncDistMirror => "",
110
+            updateDate => "",
111
+        },
112
+
113
+       mirror002 => {
114
+            orgName => "hermetix.org",
115
+            isoCC => "CA",
116
+            subRegion => "QC",
117
+            region => "North America",
118
+            ipv4 => "True",
119
+            ipv6 => "False",
120
+            loadBalanced => "Unknown",
121
+            httpWebsiteMirror => "http://tor.hermetix.org/",
122
+            rsyncWebsiteMirror => "",
123
+            httpDistMirror => "http://tor.hermetix.org/dist/",
124
+            rsyncDistMirror => "",
125
+            updateDate => "",
126
+        },
127
+
128
+       mirror003 => {
129
+            orgName => "Boinc.ch",
130
+            isoCC => "CH",
131
+            subRegion => "",
132
+            region => "Europe",
133
+            ipv4 => "True",
134
+            ipv6 => "False",
135
+            loadBalanced => "Unknown",
136
+            httpWebsiteMirror => "http://tor.boinc.ch/",
137
+            ftpWebsiteMirror => "",
138
+            rsyncWebsiteMirror => "",
139
+            httpDistMirror => "http://tor.boinc.ch/dist/",
140
+            rsyncDistMirror => "",
141
+            updateDate => "",
142
+        },
143
+
144
+       mirror004 => {
145
+            orgName => "anonymity.cn",
146
+            isoCC => "CN",
147
+            subRegion => "",
148
+            region => "Asia",
149
+            ipv4 => "True",
150
+            ipv6 => "False",
151
+            loadBalanced => "Unknown",
152
+            httpWebsiteMirror => "http://tor.anonymity.cn/",
153
+            ftpWebsiteMirror => "",
154
+            rsyncWebsiteMirror => "",
155
+            httpDistMirror => "http://tor.anonymity.cn/dist/",
156
+            rsyncDistMirror => "",
157
+            updateDate => "",
158
+        },
159
+
160
+       mirror004 => {
161
+            orgName => "bbs",
162
+            isoCC => "DE",
163
+            subRegion => "",
164
+            region => "Europe",
165
+            ipv4 => "True",
166
+            ipv6 => "False",
167
+            loadBalanced => "Unknown",
168
+            httpWebsiteMirror => "http://tor.blingblingsquad.net/",
169
+            ftpWebsiteMirror => "",
170
+            rsyncWebsiteMirror => "",
171
+            httpDistMirror => "http://tor.blingblingsquad.net/dist/",
172
+            rsyncDistMirror => "",
173
+            updateDate => "",
174
+        },
175
+
176
+       mirror005 => {
177
+            orgName => "Berapla",
178
+            isoCC => "DE",
179
+            subRegion => "",
180
+            region => "Europe",
181
+            ipv4 => "True",
182
+            ipv6 => "False",
183
+            loadBalanced => "Unknown",
184
+            httpWebsiteMirror => "http://download.berapla.de/mirrors/tor/",
185
+            ftpWebsiteMirror => "",
186
+            rsyncWebsiteMirror => "",
187
+            httpDistMirror => "",
188
+            rsyncDistMirror => "",
189
+            updateDate => "",
190
+        },
191
+
192
+       mirror006 => {
193
+            orgName => "cybermirror",
194
+            isoCC => "DE",
195
+            subRegion => "",
196
+            region => "Europe",
197
+            ipv4 => "True",
198
+            ipv6 => "False",
199
+            loadBalanced => "Unknown",
200
+            httpWebsiteMirror => "http://tor.cybermirror.org/",
201
+            ftpWebsiteMirror => "",
202
+            rsyncWebsiteMirror => "",
203
+            httpDistMirror => "http://tor.cybermirror.org/dist/",
204
+            rsyncDistMirror => "",
205
+            updateDate => "",
206
+        },
207
+
208
+       mirror007 => {
209
+            orgName => "Spline",
210
+            isoCC => "DE",
211
+            subRegion => "FU",
212
+            region => "Europe",
213
+            ipv4 => "True",
214
+            ipv6 => "False",
215
+            loadBalanced => "Unknown",
216
+            httpWebsiteMirror => "http://rem.spline.de/tor/",
217
+            ftpWebsiteMirror => "",
218
+            rsyncWebsiteMirror => "",
219
+            httpDistMirror => "",
220
+            rsyncDistMirror => "",
221
+            updateDate => "",
222
+        },
223
+
224
+       mirror008 => {
225
+            orgName => "mirror.bsdhost.eu",
226
+            isoCC => "DE",
227
+            subRegion => "",
228
+            region => "Europe",
229
+            ipv4 => "True",
230
+            ipv6 => "False",
231
+            loadBalanced => "Unknown",
232
+            httpWebsiteMirror => "http://mirror.bsdhost.eu/www.torproject.org/",
233
+            ftpWebsiteMirror => "",
234
+            rsyncWebsiteMirror => "",
235
+            httpDistMirror => "http://mirror.bsdhost.eu/www.torproject.org/dist/",
236
+            rsyncDistMirror => "",
237
+            updateDate => "",
238
+        },
239
+
240
+       mirror009 => {
241
+            orgName => "onionland",
242
+            isoCC => "DE",
243
+            subRegion => "",
244
+            region => "Europe",
245
+            ipv4 => "True",
246
+            ipv6 => "False",
247
+            loadBalanced => "Unknown",
248
+            httpWebsiteMirror => "http://mirror.onionland.org/",
249
+            ftpWebsiteMirror => "",
250
+            rsyncWebsiteMirror => "rsync: mirror.onionland.org::tor/",
251
+            httpDistMirror => "http://mirror.onionland.org/dist/",
252
+            rsyncDistMirror => "rsync: mirror.onionland.org::tor/dist/",
253
+            updateDate => "",
254
+        },
255
+
256
+       mirror010 => {
257
+            orgName => "plentyfact",
258
+            isoCC => "DE",
259
+            subRegion => "",
260
+            region => "Europe",
261
+            ipv4 => "True",
262
+            ipv6 => "False",
263
+            loadBalanced => "Unknown",
264
+            httpWebsiteMirror => "http://tor.plentyfact.net/",
265
+            ftpWebsiteMirror => "",
266
+            httpsWebsiteMirror => "https://tor.plentyfact.net/",
267
+            rsyncWebsiteMirror => "",
268
+            httpDistMirror => "http://tor.plentyfact.net/dist/",
269
+            rsyncDistMirror => "",
270
+            updateDate => "",
271
+        },
272
+
273
+       mirror011 => {
274
+            orgName => "loxal.net",
275
+            isoCC => "DE",
276
+            subRegion => "",
277
+            region => "Europe",
278
+            ipv4 => "True",
279
+            ipv6 => "False",
280
+            loadBalanced => "Unknown",
281
+            httpWebsiteMirror => "http://tor-anonymizer.mirror.loxal.net/",
282
+            ftpWebsiteMirror => "",
283
+            rsyncWebsiteMirror => "",
284
+            httpDistMirror => "http://tor-anonymizer.mirror.loxal.net/dist/",
285
+            rsyncDistMirror => "",
286
+            updateDate => "",
287
+        },
288
+
289
+       mirror012 => {
290
+            orgName => "centervenus.com",
291
+            isoCC => "DE",
292
+            subRegion => "",
293
+            region => "Europe",
294
+            ipv4 => "True",
295
+            ipv6 => "False",
296
+            loadBalanced => "Unknown",
297
+            httpWebsiteMirror => "",
298
+            ftpWebsiteMirror => "",
299
+            rsyncWebsiteMirror => "",
300
+            httpDistMirror => "http://www.centervenus.com/mirrors/tor/dist/",
301
+            rsyncDistMirror => "",
302
+            updateDate => "",
303
+        },
304
+
305
+       mirror013 => {
306
+            orgName => "zdg-gmbh.eu",
307
+            isoCC => "DK",
308
+            subRegion => "",
309
+            region => "Europe",
310
+            ipv4 => "True",
311
+            ipv6 => "False",
312
+            loadBalanced => "Unknown",
313
+            httpWebsiteMirror => "http://tor.zdg-gmbh.eu/", 
314
+            ftpWebsiteMirror => "",
315
+            rsyncWebsiteMirror => "", 
316
+            httpDistMirror => "http://tor.zdg-gmbh.eu/dist/",
317
+            rsyncDistMirror => "",
318
+            updateDate => "",
319
+        },
320
+
321
+       mirror014 => {
322
+            orgName => "CRAN",
323
+            isoCC => "FR",
324
+            subRegion => "",
325
+            region => "Europe",
326
+            ipv4 => "True",
327
+            ipv6 => "False",
328
+            loadBalanced => "Unknown",
329
+            httpWebsiteMirror => "http://tor.miroir-francais.fr/",
330
+            rsyncWebsiteMirror => "rsync: miroir-francais.fr::tor", 
331
+            ftpWebsiteMirror => "ftp://miroir-francais.fr/pub/tor/",
332
+            httpDistMirror => "",
333
+            rsyncDistMirror => "",
334
+            updateDate => "",
335
+        },
336
+
337
+       mirror015 => {
338
+            orgName => "tor.newworldorder.com.es",
339
+            isoCC => "HU",
340
+            subRegion => "",
341
+            region => "Europe",
342
+            ipv4 => "True",
343
+            ipv6 => "False",
344
+            loadBalanced => "Unknown",
345
+            httpWebsiteMirror => "http://tor.newworldorder.com.es/",
346
+            rsyncWebsiteMirror => "", 
347
+            ftpWebsiteMirror => "",
348
+            httpDistMirror => "",
349
+            rsyncDistMirror => "",
350
+            updateDate => "",
351
+        },
352
+
353
+       mirror016 => {
354
+            orgName => "amorphis.eu",
355
+            isoCC => "NL",
356
+            subRegion => "",
357
+            region => "Europe",
358
+            ipv4 => "True",
359
+            ipv6 => "False",
360
+            loadBalanced => "Unknown",
361
+            httpWebsiteMirror => "http://tor.amorphis.eu/",
362
+            rsyncWebsiteMirror => "", 
363
+            ftpWebsiteMirror => "",
364
+            httpDistMirror => "http://tor.amorphis.eu/dist/",
365
+            rsyncDistMirror => "",
366
+            updateDate => "",
367
+        },
368
+
369
+       mirror017 => {
370
+            orgName => "BIT BV",
371
+            isoCC => "NL",
372
+            subRegion => "",
373
+            region => "Europe",
374
+            ipv4 => "True",
375
+            ipv6 => "False",
376
+            loadBalanced => "Unknown",
377
+            httpWebsiteMirror => "http://ftp.bit.nl/mirror/tor/",
378
+            rsyncWebsiteMirror => "", 
379
+            ftpWebsiteMirror => "ftp://ftp.bit.nl/mirror/tor/",
380
+            httpDistMirror => "",
381
+            rsyncDistMirror => "",
382
+            updateDate => "",
383
+        },
384
+
385
+       mirror018 => {
386
+            orgName => "CCC",
387
+            isoCC => "NL",
388
+            subRegion => "",
389
+            region => "Europe",
390
+            ipv4 => "True",
391
+            ipv6 => "False",
392
+            loadBalanced => "Unknown",
393
+            httpWebsiteMirror => "http://tor.ccc.de/",
394
+            rsyncWebsiteMirror => "", 
395
+            ftpWebsiteMirror => "",
396
+            httpDistMirror => "http://tor.ccc.de/dist/",
397
+            rsyncDistMirror => "",
398
+            updateDate => "",
399
+        },
400
+
401
+       mirror018 => {
402
+            orgName => "kamagurka.org",
403
+            isoCC => "NL",
404
+            subRegion => "Haarlem",
405
+            region => "Europe",
406
+            ipv4 => "True",
407
+            ipv6 => "False",
408
+            loadBalanced => "Unknown",
409
+            httpWebsiteMirror => "http://tor.kamagurka.org/",
410
+            rsyncWebsiteMirror => "", 
411
+            ftpWebsiteMirror => "",
412
+            httpDistMirror => "http://tor.kamagurka.org/dist/",
413
+            rsyncDistMirror => "",
414
+            updateDate => "",
415
+        },
416
+
417
+       mirror019 => {
418
+            orgName => "OS Mirror",
419
+            isoCC => "NL",
420
+            subRegion => "",
421
+            region => "Europe",
422
+            ipv4 => "True",
423
+            ipv6 => "False",
424
+            loadBalanced => "Unknown",
425
+            httpWebsiteMirror => "http://tor.osmirror.nl/",
426
+            rsyncWebsiteMirror => "rsync: rsync.osmirror.nl::tor/", 
427
+            ftpWebsiteMirror => "ftp://ftp.osmirror.nl/pub/tor/",
428
+            httpDistMirror => "",
429
+            rsyncDistMirror => "",
430
+            updateDate => "",
431
+        },
432
+
433
+
434
+       mirror020 => {
435
+            orgName => "Meulie.net",
436
+            isoCC => "NO",
437
+            subRegion => "",
438
+            region => "Europe",
439
+            ipv4 => "True",
440
+            ipv6 => "False",
441
+            loadBalanced => "Unknown",
442
+            httpWebsiteMirror => "http://tor.meulie.net/",
443
+            rsyncWebsiteMirror => "", 
444
+            ftpWebsiteMirror => "",
445
+            httpDistMirror => "",
446
+            rsyncDistMirror => "",
447
+            updateDate => "",
448
+        },
449
+
450
+       mirror021 => {
451
+            orgName => "Swedish Linux Society",
452
+            isoCC => "SE",
453
+            subRegion => "",
454
+            region => "Europe",
455
+            ipv4 => "True",
456
+            ipv6 => "False",
457
+            loadBalanced => "Unknown",
458
+            httpWebsiteMirror => "http://ftp.se.linux.org/crypto/tor/",
459
+            rsyncWebsiteMirror => "", 
460
+            ftpWebsiteMirror => "ftp://ftp.se.linux.org/pub/crypto/tor/",
461
+            httpDistMirror => "",
462
+            rsyncDistMirror => "",
463
+            updateDate => "",
464
+        },
465
+
466
+       mirror022 => {
467
+            orgName => "Ghirai.com",
468
+            isoCC => "UK",
469
+            subRegion => "London",
470
+            region => "Europe",
471
+            ipv4 => "True",
472
+            ipv6 => "False",
473
+            loadBalanced => "Unknown",
474
+            httpWebsiteMirror => "http://www.ghirai.com/tor/",
475
+            rsyncWebsiteMirror => "", 
476
+            ftpWebsiteMirror => "",
477
+            httpDistMirror => "",
478
+            rsyncDistMirror => "",
479
+            updateDate => "",
480
+        },
481
+
482
+       mirror023 => {
483
+            orgName => "BJWOnline.com",
484
+            isoCC => "US",
485
+            subRegion => "California",
486
+            region => "North America",
487
+            ipv4 => "True",
488
+            ipv6 => "False",
489
+            loadBalanced => "Unknown",
490
+            httpWebsiteMirror => "http://mirror.bjwonline.com/tor/",
491
+            rsyncWebsiteMirror => "", 
492
+            ftpWebsiteMirror => "",
493
+            httpDistMirror => "",
494
+            rsyncDistMirror => "",
495
+            updateDate => "",
496
+        },
497
+
498
+       mirror024 => {
499
+            orgName => "Libertarian Action Network",
500
+            isoCC => "",
501
+            subRegion => "",
502
+            region => "North America",
503
+            ipv4 => "True",
504
+            ipv6 => "False",
505
+            loadBalanced => "Unknown",
506
+            httpWebsiteMirror => "",
507
+            rsyncWebsiteMirror => "", 
508
+            ftpWebsiteMirror => "ftp://libertarianactivism.com/tor.eff.org/dist/",
509
+            httpDistMirror => "",
510
+            rsyncDistMirror => "",
511
+            updateDate => "",
512
+        },
513
+
514
+       mirror025 => {
515
+            orgName => "TheOnionRouter.com",
516
+            isoCC => "US",
517
+            subRegion => "Texas",
518
+            region => "North America",
519
+            ipv4 => "True",
520
+            ipv6 => "False",
521
+            loadBalanced => "Unknown",
522
+            httpWebsiteMirror => "http://www.theonionrouter.com/",
523
+            rsyncWebsiteMirror => "", 
524
+            ftpWebsiteMirror => "",
525
+            httpDistMirror => "http://www.theonionrouter.com/dist/",
526
+            rsyncDistMirror => "",
527
+            updateDate => "",
528
+        },
529
+
530
+       mirror026 => {
531
+            orgName => "Site2nd.org",
532
+            isoCC => "USA",
533
+            subRegion => "Texas",
534
+            region => "North America",
535
+            ipv4 => "True",
536
+            ipv6 => "False",
537
+            loadBalanced => "Unknown",
538
+            httpWebsiteMirror => "http://tor.site2nd.org",
539
+            rsyncWebsiteMirror => "", 
540
+            ftpWebsiteMirror => "",
541
+            httpDistMirror => "",
542
+            rsyncDistMirror => "",
543
+            updateDate => "",
544
+        },
545
+
546
+       mirror027 => {
547
+            adminContact => "jeroen\@unfix.org",
548
+            orgName => "unfix",
549
+            isoCC => "CH",
550
+            subRegion => "",
551
+            region => "Europe",
552
+            ipv4 => "True",
553
+            ipv6 => "True",
554
+            loadBalanced => "Unknown",
555
+            httpWebsiteMirror => "http://tor.unfix.org/",
556
+            rsyncWebsiteMirror => "", 
557
+            ftpWebsiteMirror => "",
558
+            httpDistMirror => "",
559
+            rsyncDistMirror => "",
560
+            updateDate => "",
561
+        },
562
+
563
+       mirror028 => {
564
+            adminContact => "jeroen\@unfix.org",
565
+            orgName => "sixx",
566
+            isoCC => "",
567
+            subRegion => "",
568
+            region => "Europe",
569
+            ipv4 => "True",
570
+            ipv6 => "True",
571
+            loadBalanced => "Unknown",
572
+            httpWebsiteMirror => "http://tor.sixxs.net/",
573
+            rsyncWebsiteMirror => "", 
574
+            ftpWebsiteMirror => "",
575
+            httpDistMirror => "",
576
+            rsyncDistMirror => "",
577
+            updateDate => "",
578
+        },
579
+);
580
+
581
+my $count = values %m;
582
+print "We have a total of $count mirrors\n";
583
+print "Fetching the last updated date for each mirror.\n";
584
+
585
+foreach my $server ( keys %m ) {
586
+
587
+    print "Attempting to fetch from $m{$server}{'orgName'}\n";
588
+
589
+    if ($m{$server}{'httpWebsiteMirror'}) {
590
+        print "Attempt to fetch via HTTP.\n";
591
+        $m{$server}{"updateDate"} = FetchDate("$m{$server}{'httpWebsiteMirror'}");
592
+    } elsif ($m{$server}{'httpsWebsiteMirror'}) {
593
+        print "Attempt to fetch via HTTPS.\n";
594
+        $m{$server}{"updateDate"} = FetchDate("$m{$server}{'httpsWebsiteMirror'}");
595
+    } elsif ($m{$server}{'ftpWebsiteMirror'}) {
596
+        print "Attempt to fetch via FTP.\n";
597
+        $m{$server}{"updateDate"} = FetchDate("$m{$server}{'ftpWebsiteMirror'}");
598
+    } else {
599
+        print "We were unable to fetch or store anything. We still have the following: $m{$server}{'updateDate'}\n";
600
+    }
601
+
602
+    print "We fetched and stored the following: $m{$server}{'updateDate'}\n";
603
+
604
+ }
605
+
606
+
607
+print "We sorted the following mirrors by their date of last update: \n";
608
+foreach my $server ( sort { $m{$b}{'updateDate'} <=> $m{$a}{'updateDate'}} keys %m ) {
609
+
610
+     print "\n";
611
+     print "Mirror $m{$server}{'orgName'}: \n";
612
+
613
+     foreach my $attrib ( sort keys %{$m{$server}} ) {
614
+        print "$attrib = $m{$server}{$attrib}";
615
+        print "\n";
616
+     };
617
+}
618
+
619
+my $outFile = "include/mirrors-table.wmi";
620
+my $html;
621
+open(OUT, "> $outFile") or die "Can't open $outFile: $!";
622
+
623
+# Here's where we open a file and print some wml include goodness 
624
+# This is storted from last known recent update to unknown update times
625
+foreach my $server ( sort { $m{$b}{'updateDate'} <=> $m{$a}{'updateDate'}} keys %m ) {
626
+
627
+     # Country    Organisation    website mirror      dist/ mirror
628
+     print OUT "\n<tr>\n";
629
+     print OUT "    <td>$m{$server}{'isoCC'}</td>\n";
630
+     print OUT "    <td>$m{$server}{'orgName'}</td>\n";
631
+     print OUT "    <td>$m{$server}{'updateDate'}</td>\n";
632
+
633
+     foreach my $precious ( "httpWebsiteMirror", "ftpWebsiteMirror", 
634
+                            "rsyncWebsiteMirror","httpDistMirror",
635
+                            "rsyncDistMirror" )
636
+     {
637
+        if ($m{$server}{"$precious"}) {
638
+            print OUT "    <td><a href=\"" . $m{$server}{$precious} . "\">" .
639
+                      "$m{$server}{$precious}</a></td>\n";
640
+        } else { print OUT "    <td> - </td>\n"; }
641
+     }
642
+
643
+     print OUT "</tr>\n";
644
+}
645
+
646
+close(OUT);