Annotation of 2002/scribe/scribe.perl, revision 1.23
1.7 dbooth 1: #! perl -w
1.1 dbooth 2:
1.20 dbooth 3: warn 'This is $Revision: 1.14 $ of $Date: 2003/06/13 21:02:20 $
1.11 dbooth 4: Check for newer version at http://dev.w3.org/cvsweb/~checkout~/2002/scribe/
5:
6: ';
7:
8:
1.7 dbooth 9: # Generate minutes in HTML from a text IRC/chat Log.
10: #
1.1 dbooth 11: # Author: David Booth <dbooth@w3.org>
1.3 dbooth 12: #
1.1 dbooth 13: # Take a raw W3C IRC log, tidy it up a bit, and put it into HTML
14: # to create meeting minutes. Reads stdin, writes stdout.
1.7 dbooth 15: # Several input formats are accepted (see below).
16: # Input must follow certain conventions (see below).
1.16 dbooth 17: #
1.5 dbooth 18: # USAGE:
1.3 dbooth 19: # perl scribe.perl [options] ircLogFile.txt > minutesFile.htm
20: # perl scribe.perl -sampleInput
21: # perl scribe.perl -sampleOutput
22: # perl scribe.perl -sampleTemplate
1.1 dbooth 23: #
24: # Options:
1.3 dbooth 25: # -sampleInput Show me some sample input, so I can
26: # learn how to use this program.
27: #
28: # -sampleOutput Show me some sample output.
29: #
1.1 dbooth 30: # -scribeOnly Only keep scribe statements. (Otherwise
31: # everyone's statements are kept.)
32: #
1.3 dbooth 33: # -template tfile Use tfile as the template file for
34: # generating the HTML. Without this option,
35: # the program will default to an embedded
36: # template, which you can see by using
37: # the "-sampleTemplate" option.
38: #
39: # -sampleTemplate Show me a sample template file.
1.5 dbooth 40: # (The default template.)
41: #
42: # -public Use a template that is formatted
43: # for public access. DEFAULT.
44: # (Search for "sub PublicTemplate" below.)
45: #
46: # -member Use a template that is formatted
47: # for W3C member-only access.
48: # (Search for "sub PublicTemplate" below.)
49: #
50: # -team Use a template that is formatted
51: # for W3C team-only access.
52: # (Search for "sub PublicTemplate" below.)
53: #
54: # -mit Use a template that is formatted for
55: # W3C MIT style.
56: # (Search for "sub PublicTemplate" below.)
1.3 dbooth 57: #
1.1 dbooth 58: # The best way to use this program is:
59: # 1. Make a backup of your IRC log.
1.5 dbooth 60: # 2. Modify the IRC log to conform to the scribe conventions that this
1.3 dbooth 61: # program expects (described below).
62: # 3. Run this program as described above.
1.1 dbooth 63: # 4. View the output in a browser.
1.3 dbooth 64: # 5. Go back to step 2 to make modifications, and repeat.
65: # Once the output looks good enough, then . . .
66: # 6. Manually edit the resulting HTML for any remaining fixes.
1.1 dbooth 67: #
1.5 dbooth 68: # SCRIBE CONVENTIONS:
1.1 dbooth 69: # This program expects certain conventions in the IRC log as follows.
1.17 dbooth 70: # Identify the IRC name of the scribe (Note that names must not contain spaces):
1.7 dbooth 71: # <dbooth> Scribe: dbooth
1.1 dbooth 72: # Identify the meeting chair:
1.7 dbooth 73: # <dbooth> Chair: Jonathan
1.1 dbooth 74: # Identify the meeting itself:
1.7 dbooth 75: # <dbooth> Meeting: Weekly Baking Club Meeting
1.11 dbooth 76: # Fix the meeting date (default is auto set from IRC log name or today if
77: # there is no "Date:" line):
1.3 dbooth 78: # <dbooth> Date: 05 Dec 2002
1.1 dbooth 79: # Identify the current topic. You should insert one of
80: # these lines before the start of EACH topic:
81: # <dbooth> Topic: Review of Action Items
82: # Record an action item:
83: # <dbooth> ACTION: dbooth to send a message to himself about action items
1.11 dbooth 84: # Record an incomplete action item (either syntax):
1.7 dbooth 85: # <Philippe> PENDING ACTION: Barbara to bake 3 pies
1.11 dbooth 86: # <Philippe> ACTION: Barbara to bake 3 pies -- PENDING
87: # Record a completed action item (either syntax):
88: # <Philippe> DONE ACTION: Barbara to bake 3 pies
89: # <Philippe> ACTION: Barbara to bake 3 pies -- DONE
1.1 dbooth 90: # Scribe someone's statements:
1.7 dbooth 91: # <dbooth> Joseph: I think that we should all eat cake
92: # <dbooth> ... with ice creme.
1.11 dbooth 93: # Correct a mistake (changes most recent instance):
1.1 dbooth 94: # <dbooth> s/creme/cream/
95: # Correct a mistake globally from this point back in the input:
96: # <dbooth> s/Baking/Cooking/g
1.16 dbooth 97: # Identify the IRC log produced by RRSAGENT (this also sets the date):
1.1 dbooth 98: # <dbooth> rrsagent, where am i?
1.7 dbooth 99: # <RRSAgent> See http://www.w3.org/2002/11/07-ws-arch-irc#T13-59-36
1.5 dbooth 100: # or:
101: # <dbooth> Log: http://www.w3.org/2002/11/07-ws-arch-irc
1.8 dbooth 102: # Separator (at least 4 dashes):
103: # <dbooth> ----
1.1 dbooth 104: #
1.11 dbooth 105: # INPUT FORMATS ACCEPTED
106: # These formats are auto detected. The best match wins.
1.7 dbooth 107: # MIRC buffer style:
108: # <ericn> Where is our next F2F?
109: # <dbooth> Rennes France.
110: # RRSAgent Text style:
111: # 20:41:27 <ericn> Where is our next F2F?
112: # 20:41:37 <dbooth> Rennes France.
113: # RRSAgent HTML style:
114: # <dt id="T20-41-27">20:41:27 [ericn]</dt><dd>Where is our next F2F? </dd>
115: # <dt id="T20-41-37">20:41:37 [dbooth]</dt><dd>Rennes France. </dd>
116: # RRSAgent HTML Text style (text copied and pasted from the browser):
117: # 20:41:27 [ericn]
118: # Where is our next F2F?
119: # 20:41:37 [dbooth]
120: # Rennes France.
121: # Yahoo IM style:
122: # ericn: Where is our next F2F?
123: # dbooth: Rennes France.
124: #
1.3 dbooth 125: # WARNING: The code is a horrible mess. (Sorry!) Please hold your nose if
1.16 dbooth 126: # you look at it. If you have something better, or make improvements
127: # to this (and please do!), please let me know. Perhaps it's a good
128: # example of Fred Brooke's advice in Mythical Man Month: "Plan to throw
129: # one away".
1.1 dbooth 130: #
1.3 dbooth 131: ######################################################################
1.1 dbooth 132:
1.7 dbooth 133: my $scribeName = "UNKNOWN"; # Default
134:
135: # Formatting:
136: # my $preSpeakerHTML = "<strong>";
137: # my $postSpeakerHTML = "</strong> <br />";
138: my $preSpeakerHTML = "<b>";
139: my $postSpeakerHTML = "</b>";
140: my $preParagraphHTML = "<p>";
141: my $postParagraphHTML = "</p>";
1.15 hugo 142: my $preTopicHTML = "<h3";
1.7 dbooth 143: my $postTopicHTML = "</h3>";
1.1 dbooth 144:
145: # Get options/args
1.3 dbooth 146: my $all = ""; # Input
1.1 dbooth 147: my $canonicalizeNames = 0; # Convert all names to their canonical form?
1.7 dbooth 148: my $useTeamSynonyms = 0; # Accept any short synonyms for team members?
1.1 dbooth 149: my $scribeOnly = 0; # Only select scribe lines
1.11 dbooth 150:
151: @ARGV = map {glob} @ARGV; # Expand wildcards in arguments
1.1 dbooth 152: my @args = ();
1.5 dbooth 153: my $template = &DefaultTemplate();
1.1 dbooth 154: while (@ARGV)
155: {
156: my $a = shift @ARGV;
157: if (0) {}
1.3 dbooth 158: elsif ($a eq "-sampleInput")
159: { print STDOUT &SampleInput(); exit 0; }
160: elsif ($a eq "-sampleOutput")
161: { $all = &SampleInput(); }
162: elsif ($a eq "-sampleTemplate")
163: { print STDOUT &DefaultTemplate(); exit 0; }
1.1 dbooth 164: elsif ($a eq "-scribeOnly")
165: { $scribeOnly = 1; }
166: elsif ($a eq "-canon")
167: { $canonicalizeNames = 1; }
168: elsif ($a eq "-teamSynonyms")
169: { $useTeamSynonyms = 1; }
170: elsif ($a eq "-mit")
1.5 dbooth 171: { $template = &MITTemplate(); }
1.1 dbooth 172: elsif ($a eq "-team")
1.5 dbooth 173: { $template = &TeamTemplate(); }
1.1 dbooth 174: elsif ($a eq "-member")
1.5 dbooth 175: { $template = &MemberTemplate(); }
1.1 dbooth 176: elsif ($a eq "-world")
1.5 dbooth 177: { $template = &PublicTemplate(); }
1.1 dbooth 178: elsif ($a eq "-public")
1.5 dbooth 179: { $template = &PublicTemplate(); }
1.1 dbooth 180: elsif ($a eq "-template")
1.5 dbooth 181: {
182: my $templateFile = shift @ARGV;
183: die "ERROR: Template file not found: $templateFile\n"
184: if !-e $templateFile;
1.7 dbooth 185: my $t = &GetTemplate($templateFile);
1.5 dbooth 186: if (!$t)
187: {
188: die "ERROR: Empty template: $templateFile\n";
189: }
190: $template = $t;
191: }
1.1 dbooth 192: elsif ($a =~ m/\A\-/)
193: { die "ERROR: Unknown option: $a\n"; }
194: else
195: { push(@args, $a); }
196: }
197: @ARGV = @args;
198:
1.7 dbooth 199: # Get input:
200: $all = join("",<>) if !$all;
1.1 dbooth 201: if (!$all)
202: {
1.3 dbooth 203: warn "WARNING: Empty input.\n";
1.1 dbooth 204: }
205: # Delete control-M's if any.
206: $all =~ s/\r//g;
1.7 dbooth 207:
1.8 dbooth 208: # Normalize input format. To do so, we need to guess the input format.
209: # Try each known formats, and see which one matches best.
1.7 dbooth 210: my $bestScore = 0;
211: my $bestAll = "";
212: my $bestName = "";
1.8 dbooth 213: # These are the normalizer functions we'll be calling.
1.11 dbooth 214: # Each one is defined below.
1.8 dbooth 215: # Just add another to the list if you want to recognize another format.
1.11 dbooth 216: # Each function takes $all (the input text) as input and returns
217: # a pair: ($score, $newAll).
218: # $score is a value [0,1] indicating how well it matched.
219: # $newAll is the normalized input.
1.7 dbooth 220: foreach my $f (qw(
221: NormalizerMircTxt
1.8 dbooth 222: NormalizerRRSAgentText
1.7 dbooth 223: NormalizerRRSAgentHtml
224: NormalizerRRSAgentHTMLText
225: NormalizerYahoo
1.20 dbooth 226: NormalizerPlainText
1.7 dbooth 227: ))
228: {
229: my ($score, $newAll) = &$f($all);
230: # warn "$f: $score\n";
231: if ($score > $bestScore)
232: {
233: $bestScore = $score;
234: $bestAll = $newAll;
235: $bestName = $f;
236: }
237: }
238: my $bestScoreString = sprintf("%4.2f", $bestScore);
239: warn "Input format (score $bestScoreString): $bestName\n";
1.8 dbooth 240: die "ERROR: Could not guess input format.\n" if $bestScore == 0;
241: warn "WARNING: Low confidence ($bestScoreString) on guessing input format: $bestName\n"
1.7 dbooth 242: if $bestScore < 0.7;
243: $all = $bestAll;
244:
1.9 dbooth 245:
1.7 dbooth 246: # Perform s/old/new/ substitutions.
247: while($all =~ m/\n\<[^\>]+\>\s*s\/([^\/]+)\/([^\/]*?)((\/(g))|\/?)(\s*)\n/i)
248: {
249: my $old = $1;
250: my $new = $2;
1.4 dbooth 251: my $global = $5;
1.7 dbooth 252: my $pre = $`;
253: my $match = $&;
254: my $post = $';
255: my $oldp = quotemeta($old);
1.1 dbooth 256: # warn "Found match: $match\n";
257: my $told = $old;
258: $told = $& . "...(truncated)...." if ($old =~ m/\A.*\n/);
259: my $tnew = $new;
260: $tnew = $& . "...(truncated)...." if ($old =~ m/\A.*\n/);
261: my $succeeded = 0;
262: if (($global && $pre =~ s/$oldp/$new/g)
1.7 dbooth 263: || ((!$global) && $pre =~ s/\A((.|\n)*)($oldp)((.|\n)*?)\Z/$1$new$4/))
264: {
265: warn "SUBSTITUTION: s/$told/$tnew/\n";
1.1 dbooth 266: warn "(global substitution)\n" if $global;
1.7 dbooth 267: $all = $pre . "\n" . $post;
268: }
269: else {
270: warn "s/$told/$tnew/ FAILED\n";
271: $match =~ s/\A\s+//;
272: $match =~ s/\s+\Z//;
273: $all = $pre . "\n[Auto substitution failed:] " . $match . "\n" . $post;
274: }
1.1 dbooth 275: warn "WARNING: Multiline substitution!!! (Is this correct?)\n" if $tnew ne $new || $told ne $old;
1.7 dbooth 276: }
277:
278: # Strip -home from names. (Convert alan-home to alan, for example.)
279: $all =~ s/(\w+)\-home\b/$1/ig;
280: # Strip -lap from names. (Convert alan-lap to alan, for example.)
281: $all =~ s/(\w+)\-lap\b/$1/ig;
282: # Strip -iMac from names. (Convert alan-iMac to alan, for example.)
283: $all =~ s/(\w+)\-iMac\b/$1/ig;
284:
285: # Determine scribe name if possible:
286: $scribeName = $3 if $all =~ s/\s+scribe\s+((today\s+)?)is\s+([\w\-]+)//i;
287: $scribeName = $1 if $all =~ s/\s+scribe\s*\:\s*([\w\-]+)//i;
288: $scribeName = $1 if $all =~ s/\s([\w\-]+)\s+is\s+scribe//i;
289: $scribeName = $1 if $all =~ s/\s([\w\-]+)\s+is\s+scribing//i;
290: $scribeName = $1 if $all =~ s/\<([^\>\ ]+)\>\s*I\s+am\s+scribe\s+.*//i;
291: $scribeName = $1 if $all =~ s/\<([^\>\ ]+)\>\s*I\s+will\s+scribe\s+.*//i;
292: $scribeName = $1 if $all =~ s/\<([^\>\ ]+)\>\s*I\s+am\s+scribing.*//i;
293: warn "Scribe: $scribeName\n";
294:
295: # Get attendee list, and normalize names within the document:
1.17 dbooth 296: my $namePattern = '([\\w]([\\w\\d\\-]*))';
1.1 dbooth 297: # warn "namePattern: $namePattern\n";
1.7 dbooth 298: my @uniqNames = ();
1.1 dbooth 299: my $allNameRefsRef;
300: ($all, $scribeName, $allNameRefsRef, @uniqNames) = &GetNames($all, $scribeName);
301: my @allNames = map { ${$_} } @{$allNameRefsRef};
1.7 dbooth 302: my $scribePattern = quotemeta($scribeName);
1.1 dbooth 303: $all =~ s/\<$scribePattern\>/\<Scribe\>/ig;
304: $scribePattern = "Scribe";
305: push(@allNames,"Scribe");
306: my @allSpeakerPatterns = map {quotemeta($_)} @allNames;
307: my $speakerPattern = "((" . join(")|(", @allSpeakerPatterns) . "))";
308: # warn "speakerPattern: $speakerPattern\n";
309:
310: # Escape &
311: $all =~ s/\&/\&\;/g;
312:
313: # Normalize Scribe continuation lines so that the speaker's name is on every line:
314: # <Scribe> SusanW: We had a mtg on July 16.
315: # <DanC_> pointer to minutes?
1.8 dbooth 316: # <Scribe> SusanW: I'm looking.
1.1 dbooth 317: # <Scribe> ... The minutes are on the admin timeline page.
318: my @allLines = split(/\n/, $all);
319: my $currentSpeaker = "UNKNOWN_SPEAKER";
320: for (my $i=0; $i<@allLines; $i++)
321: {
322: # warn "$allLines[$i]\n";
323: if ($allLines[$i] =~ m/\A\<Scribe\>\s*($speakerPattern)\s*\:/i)
324: {
325: $currentSpeaker = $1;
326: # warn "SET SPEAKER: $currentSpeaker\n";
327: }
328: elsif ($allLines[$i] =~ s/\A\<Scribe\>\s*\.\.+\s*/\<Scribe\> $currentSpeaker: /i)
329: {
330: # warn "Scribe NORMALIZED: $& --> $allLines[$i]\n";
331: warn "WARNING: UNKNOWN SPEAKER: $allLines[$i]\nPossibly need to add line; <Zakim> +someone\n" if $currentSpeaker eq "UNKNOWN_SPEAKER";
332: }
333: elsif ($allLines[$i] =~ m/\A\<Scribe\>\s*($namePattern)\s*\:/i)
334: {
335: # This doesn't work right. It matches "Topic:" and known names.
336: # warn "Possibly need to add speaker \"$1\" by adding line:\n<Zakim> +$1\n";
337: }
338: }
339: $all = "\n" . join("\n", @allLines) . "\n";
340:
341: # Get the list of people present:
1.7 dbooth 342: my @possiblyPresent = @uniqNames; # People present at the meeting
343: my @present = (); # People present at the meeting
1.14 dbooth 344: while ($all =~ s/\s+Present\s*\:\s*(.*)//i)
1.7 dbooth 345: {
346: my $present = $1;
1.14 dbooth 347: my @p = ();
1.7 dbooth 348: if ($present =~ m/\,/)
349: {
350: # Comma-separated list
1.14 dbooth 351: @p = grep {$_ && $_ ne "and"}
352: map {s/\A\s+//; s/\s+\Z//; s/\s+/_/g; $_}
1.7 dbooth 353: split(/\,/,$present);
354: }
355: else {
356: # Space-separated list
1.14 dbooth 357: @p = grep {$_} split(/\s+/,$present);
1.7 dbooth 358: }
1.14 dbooth 359: if (scalar(@p) < scalar(@present))
1.7 dbooth 360: {
1.14 dbooth 361: warn "\nWARNING: Combining \"$present\"
362: with previous list of people present.\n\n";
363: my %seen = map {($_,$_)} @present;
364: my @newp = grep {!exists($seen{$_})} @p;
365: push(@present, @newp);
366: }
367: else {
368: warn "\nWARNING: Replacing previous list of people present.\n\n" if @present;
369: @present = @p;
370: }
371: warn "Present: @present\n";
372: }
373: if (@present < 3)
374: {
375: if (@present > 0) { warn "WARNING: Fewer than 3 people found present!\n\n"; }
376: else {
1.16 dbooth 377: warn "\nWARNING: No \"Present: ... \" found!\n";
1.14 dbooth 378: warn "Possibly Present: @possiblyPresent\n";
379: warn "You can indicate the people present like this:
380: <scribe> Present: dbooth jonathan mary\n\n";
1.7 dbooth 381: }
382: }
1.1 dbooth 383:
384: # Get the list of regrets:
385: my @regrets = (); # People who sent regrets
1.7 dbooth 386: if ($all =~ s/\s+Regrets\s*\:\s*(.*)//i)
387: {
388: my $regrets = $1;
389: if ($regrets =~ m/\,/)
390: {
391: # Comma-separated list
392: @regrets = grep {$_ && $_ ne "and"}
393: map {s/\As+//; s/s\+\Z//; $_}
394: split(/\,/,$regrets);
395: }
396: else {
397: # Space-separated list
398: @regrets = grep {$_} split(/\s+/,$regrets);
399: }
400: }
401: warn "Regrets: @regrets\n" if @regrets;
1.1 dbooth 402:
1.7 dbooth 403: # Grab meeting name:
1.8 dbooth 404: my $title = "SV_MEETING_TITLE";
1.14 dbooth 405: if ($all =~ s/\n\<$namePattern\>\s*(Meeting|Title)\s*\:\s*(.*)\n/\n/i)
406: { $title = $4; }
407: else {
408: warn "\nWARNING: No meeting title found!
409: You should specify the meeting title like this:
410: <scribe> Meeting: Weekly Baking Club Meeting\n\n";
411: }
1.7 dbooth 412:
413: # Grab Previous meeting URL:
1.8 dbooth 414: my $previousURL = "SV_PREVIOUS_MEETING_URL";
1.14 dbooth 415: if ($all =~ s/\n\<$namePattern\>\s*(Previous|PreviousMeeting|Previous Meeting)\s*\:\s*(.*)\n/\n/i)
416: { $previousURL = $4; }
1.7 dbooth 417:
418: # Grab Chair:
1.8 dbooth 419: my $chair = "SV_MEETING_CHAIR";
1.14 dbooth 420: if ($all =~ s/\n\<$namePattern\>\s*(Chair(s?))\s*\:\s*(.*)\n/\n/i)
421: { $chair = $5; }
422: else {
423: warn "\nWARNING: No meeting chair found!
424: You should specify the meeting chair like this:
425: <scribe> Chair: dbooth\n\n";
426: }
1.7 dbooth 427:
1.10 dbooth 428: # Grab IRC Log URL. Do this before looking for the date, because
429: # we can figure out the date from the IRC log name.
1.8 dbooth 430: my $logURL = "SV_MEETING_IRC_URL";
1.7 dbooth 431: # <RRSAgent> recorded in http://www.w3.org/2002/04/05-arch-irc#T15-46-50
432: $logURL = $3 if $all =~ m/\n\<(RRSAgent|Zakim)\>\s*(recorded|logged)\s+in\s+(http\:([^\s\#]+))/i;
433: $logURL = $6 if $all =~ s/\n\<$namePattern\>\s*(IRC|Log|(IRC(\s*)Log))\s*\:\s*(.*)\n/\n/i;
434: $logURL = $3 if $all =~ m/\n\<(RRSAgent|Zakim)\>\s*(see|recorded\s+in)\s+(http\:([^\s\#]+))/i;
435:
1.10 dbooth 436: # Grab and remove date from $all
1.20 dbooth 437: my ($day0, $mon0, $year, $monthAlpha) = &GetDate($all, $namePattern, $logURL);
1.10 dbooth 438:
1.21 dbooth 439: # Grab all ACTION items (whether new, done, pending, or dropped):
1.7 dbooth 440: # <dbooth> ACTION: MSM to report back on XMLP IPR policy after W3M mtg.
441: # <dbooth> ACTION: MSM to report back on XMLP IPR policy after W3M mtg. [4]
1.21 dbooth 442: # <dbooth> DONE ACTION: MSM to report back on XMLP IPR policy after W3M mtg.
443: # <dbooth> PENDING ACTION: MSM to report back on XMLP IPR policy after W3M mtg.
444: # <dbooth> ACTION: MSM to report back on XMLP IPR policy after W3M mtg. -- DONE
445: # <dbooth> ACTION: MSM to report back on XMLP IPR policy after W3M mtg. -- PENDING
446: # <dbooth> ACTION: MSM to report back on XMLP IPR policy after W3M mtg. * DONE *
447: # <dbooth> ACTION: MSM to report back on XMLP IPR policy after W3M mtg. * PENDINGa *
448: my %actions = (); # Key: action Value: (NEW|DONE|PENDING|DROPPED)
449: # warn "ALL ACTIONs:\n";
450: $t = "\n" . $all;
451: # $t .= "<dbooth> [PENDING] ACTION: My fake action text1\n"; # Test
452: # $t .= "<dbooth> *PENDING* ACTION: My fake action text2\n"; # Test
453: # $t .= "<dbooth> PENDING ACTION: My fake action text3\n"; # Test
454: # $t .= "<dbooth> ACTION: My fake action text4 (PENDING)\n"; # Test
455: # $t .= "<dbooth> ACTION: My fake action text5 PENDING\n"; # Test
456: # $t .= "<dbooth> ACTION: My fake action text6 *PENDING*\n"; # Test
457: while ($t =~ s/(.|\n)*?\n\<[^\>]+\>\s*[\[\(\-\*\s]*(((NEW)}(DONE)|(PENDING)|(DROPPED))[\]\)\-\*\s]*\s+)?ACTION\s*\:\s*(.*?)\s*\n/\n/)
458: {
459: my $action = $8;
460: my $status = $3 ? $3 : "NEW";
461: # warn "action: $action status: $status\n";
1.7 dbooth 462: $action =~ s/\A\s+//;
463: $action =~ s/\s+\Z//;
464: $action =~ s/\s*\[\d+\]\Z//; # Remove action numbers: [4]
1.21 dbooth 465: $status = $1 if $action =~ s/[\[\(\-\*\s]+((NEW)|(DONE)|(PENDING)|(DROPPED))[\]\)\-\*\s]*\Z//i;
1.7 dbooth 466: next if exists($actions{$action});
1.21 dbooth 467: $actions{$action} = $status;
468: # warn "ACTION: '$action' STATUS: '$status'\n";
1.7 dbooth 469: }
470:
471: # Get a list of people who have action items:
472: my %actionPeople = ();
1.21 dbooth 473: foreach my $a ((keys %actions))
1.7 dbooth 474: {
475: # warn "action:$a:\n";
476: if ($a =~ m/\s+(to)\s+/i)
477: {
478: my $pre = $`;
479: my @names = split(/[^a-zA-Z0-9\-\_]+/,$pre);
480: # warn "names: @names\n";
481: foreach my $n (@names)
482: {
483: next if $n eq "";
484: next if $n eq "and";
485: $actionPeople{$n} = $n;
486: }
487: }
488: elsif ($a =~ m/\A([a-zA-Z0-9\-\_]+)/)
489: {
490: my $n = $1;
491: $actionPeople{$n} = $n;
492: }
493: else {
494: warn "NO PERSON FOUND FOR ACTION: $a\n";
495: }
496: }
497: warn "People with action items: ",join(" ", keys %actionPeople), "\n";
1.1 dbooth 498:
1.21 dbooth 499: # Format the resulting action items:
500: # warn "ACTIONS:\n";
501: # my $actionTemplate = "<strong>ACTION:</strong> \$action <strong>[\$status]</strong> <br />\n";
502: my $actionTemplate = "<strong>[\$status]</strong> <strong>ACTION:</strong> \$action <br />\n";
503: my $formattedActions = "";
1.23 ! dbooth 504: foreach my $status (qw(PENDING NEW DROPPED DONE))
1.21 dbooth 505: {
506: foreach my $action (keys %actions)
507: {
508: next if $actions{$action} ne $status;
509: my $s = $actionTemplate;
510: $s =~ s/\$action/$action/;
511: $s =~ s/\$status/$status/;
512: $formattedActions .= $s;
513: delete($actions{$action});
514: }
515: $formattedActions .= "<br />\n\n";
516: }
517: foreach my $status (qw(DONE DROPPED))
518: {
519: foreach my $action (keys %actions)
520: {
521: next if $actions{$action} ne $status;
522: # Don't need to do anything for the done or dropped actions.
523: delete($actions{$action});
524: }
525: }
526: # There shouldn't be any more kinds of actions, but if there are, format them
527: # $actions{'FAKE ACTION TEXT'} = 'OTHER_STATUS'; # Test
528: foreach my $status (sort values %actions)
529: {
530: foreach my $action (keys %actions)
531: {
532: next if $actions{$action} ne $status;
533: my $s = $actionTemplate;
534: $s =~ s/\$action/$action/;
535: $s =~ s/\$status/$status/;
536: $formattedActions .= $s;
537: delete($actions{$action});
538: }
539: $formattedActions .= "<br />\n\n";
540: }
541:
1.1 dbooth 542: # Ignore off-record lines and other lines that should not be minuted.
1.7 dbooth 543: my @lines = split(/\n/, $all);
544: my $nLines = scalar(@lines);
545: warn "Lines found: $nLines\n";
546: my @scribeLines = ();
1.1 dbooth 547: foreach my $line (@lines)
548: {
549: # Ignore /me lines
550: next if $line =~ m/\A\s*\*/;
551: # Select only <speaker> lines
552: next if $line !~ m/\A\<$namePattern\>/i;
553: # Ignore empty lines
554: next if $line =~ m/\A\<$namePattern\>\s*\Z/i;
555: # Ignore join/leave lines:
556: next if $line =~ m/\A\s*\<($namePattern)\>\s*\1\s+has\s+(joined|left|departed|quit)\s*((\S+)?)\s*\Z/i;
557: next if $line =~ m/\A\s*\<(Scribe)\>\s*$namePattern\s+has\s+(joined|left|departed|quit)\s*((\S+)?)\s*\Z/i;
1.4 dbooth 558: # Ignore topic change lines:
559: # <geoff_a> geoff_a has changed the topic to: Trout Mask Replica
560: next if $line =~ m/\A\s*\<($namePattern)\>\s*\1\s+(has\s+changed\s+the\s+topic\s+to\s*\:.*)\Z/i;
1.1 dbooth 561: # Ignore zakim lines
562: next if $line =~ m/\A\<Zakim\>/i;
563: next if $line =~ m/\A\<$namePattern\>\s*zakim\s*\,/i;
1.20 dbooth 564: next if $line =~ m/\A\<$namePattern\>\s*agenda\s*\d*\s*[\+\-\=\?]/i;
1.14 dbooth 565: next if $line =~ m/\A\<$namePattern\>\s*close\s+agend(a|(um))\s+\d+\Z/i;
566: next if $line =~ m/\A\<$namePattern\>\s*open\s+agend(a|(um))\s+\d+\Z/i;
567: next if $line =~ m/\A\<$namePattern\>\s*take\s+up\s+agend(a|(um))\s+\d+\Z/i;
1.11 dbooth 568: next if $line =~ m/\A\<$namePattern\>\s*q\s*[\+\-\=\?]/i;
1.14 dbooth 569: next if $line =~ m/\A\<$namePattern\>\s*ack\s+$namePattern\s*\Z/i;
1.1 dbooth 570: # Ignore RRSAgent lines
571: next if $line =~ m/\A\<RRSAgent\>/i;
572: next if $line =~ m/\A\<$namePattern\>\s*RRSAgent\s*\,/i;
573: # Remove off the record comments:
574: next if $line =~ m/\A\<$namePattern\>\s*\[\s*off\s*\]/i;
1.11 dbooth 575: # Select only <scribe> lines?
1.1 dbooth 576: next if $scribeOnly && $line !~ m/\A\<Scribe\>/i;
577: # warn "KEPT: $line\n";
578: push(@scribeLines, $line);
579: }
1.7 dbooth 580: my $nScribeLines = scalar(@scribeLines);
581: warn "Minuted lines found: $nScribeLines\n";
1.1 dbooth 582: @lines = @scribeLines;
583:
584: # Verify that we axed all join/leave lines:
585: {
586: my $all = join("\n", @lines);
587: my @matches = ($all =~ m/.*has joined.*\n/g);
588: warn "WARNING: Possible join/leave lines remaining: \n\t" . join("\t", @matches)
589: if @matches;
590: }
591:
592: # Convert from:
593: # <Scribe> DanC: something
594: # <Scribe> DanC: something
595: # <DanC> something
596: # <DanC> something
597: # <Scribe> DanC: something
1.8 dbooth 598: # <Scribe> ----
599: # <Scribe> Whatever
1.1 dbooth 600: # to:
601: # DanC: something
602: # ... something
603: # <DanC> something
604: # ... something
605: # DanC: something
1.8 dbooth 606: # ----------------------------------------
607: # <Scribe> Whatever
1.1 dbooth 608:
609: my $prevSpeaker = "UNKNOWN_SPEAKER:"; # "DanC:" or "<DanC>"
610: my $prevPattern = quotemeta($prevSpeaker);
611: foreach my $line (@lines)
612: {
613: # warn "$line";
614: if ($line =~ m/\A\<$namePattern\>\s*Topic\s*\:/i )
615: {
616: # New topic.
617: # Force the speaker name to be repeated next time
618: $prevSpeaker = "UNKNOWN_SPEAKER:"; # "DanC:" or "<DanC>"
619: $prevPattern = quotemeta($prevSpeaker);
620: }
1.8 dbooth 621: # Separator:
622: # <Scribe> ----
623: elsif ($line =~ m/\A(\<$namePattern\>)\s*\-\-\-\-+\s*\Z/i)
624: {
625: my $dashes = '-' x 30;
626: $line = $dashes;
627: }
628: # Separator:
629: # <Scribe> ====
630: elsif ($line =~ m/\A(\<$namePattern\>)\s*\=\=\=\=+\s*\Z/i)
631: {
632: my $dashes = '=' x 30;
633: $line = $dashes;
634: }
1.1 dbooth 635: elsif ($line =~ s/\A\<Scribe\>\s*($prevPattern)\s*/ ... /i )
636: {
637: }
638: elsif ($line =~ s/\A\<Scribe\>\s*($speakerPattern\:)\s*/$1 /i )
639: {
640: # New speaker
641: $prevSpeaker = "$1";
642: $prevPattern = quotemeta($prevSpeaker);
643: }
644: elsif ($line =~ s/\A$prevPattern\s*/ ... /i)
645: {
646: }
647: elsif ($line =~ s/\A(\<Scribe\>)\s*/Scribe\: /i )
648: {
649: # Scribe speaks
650: $prevSpeaker = $1;
651: $prevPattern = quotemeta($prevSpeaker);
652: }
653: elsif ($line =~ m/\A(\<$namePattern\>)/i)
654: {
655: $prevSpeaker = $1;
656: $prevPattern = quotemeta($prevSpeaker);
657: }
658: else {
659: die "DIED FROM UNKNOWN LINE FORMAT: $line\n";
660: }
661: }
662:
1.7 dbooth 663: $all = join("\n", @lines);
664: $all = "\n" . $all . "\n"; # Easier pattern matching
1.1 dbooth 665:
666: ############## Escape < > as < > ################
1.7 dbooth 667: # Escape < and >:
668: $all =~ s/\</\<\;/g;
669: $all =~ s/\>/\>\;/g;
670:
671: # Format topic titles (i.e., collect agenda):
672: my %agenda = ();
673: my $itemNum = "item01";
1.15 hugo 674: while ($all =~ s/\n(\<\;$namePattern\>\;\s+)?Topic\:\s*(.*)\n/\n$preTopicHTML id\=\"$itemNum\"\>$4$postTopicHTML\n/i)
1.7 dbooth 675: {
676: $agenda{$itemNum} = $4;
677: $itemNum++;
678: }
1.13 dbooth 679: if (!scalar(keys %agenda)) # No "Topic:"s found?
680: {
681: warn "\nWARNING: No \"Topic: ...\" lines found! \nResulting HTML may have an empty (invalid) <ol>...</ol>.\n\nExplanation: \"Topic: ...\" lines are used to indicate the start of \nnew discussion topics or agenda items, such as:\n<dbooth> Topic: Review of Amy's report\n\n";
682: }
1.7 dbooth 683: my $agenda = "";
684: foreach my $item (sort keys %agenda)
685: {
686: $agenda .= '<li><a href="#' . $item . '">' . $agenda{$item} . "</a></li>\n";
687: }
1.1 dbooth 688:
1.7 dbooth 689: # Break into paragraphs:
1.1 dbooth 690: $all =~ s/\n(([^\ \.\<].*)(\n\ *\.\.+.*)*)/\n$preParagraphHTML\n$1\n$postParagraphHTML\n/g;
691:
1.7 dbooth 692: # Highlight in-line ACTION items:
693: $all =~ s/(\n)ACTION\:/$1\<strong\>ACTION\:\<\/strong\>/g;
694: $all =~ s/(\n\<\;$namePattern\>\;\ +)ACTION\:/$1\<strong\>ACTION\:\<\/strong\>/g;
1.1 dbooth 695:
1.7 dbooth 696: # Bold or <strong> speaker name:
1.1 dbooth 697: # Change "<speaker> ..." to "<b><speaker><b> ..."
698: my $preUniq = "PreSpEaKerHTmL";
699: my $postUniq = "PostSpEaKerHTmL";
1.7 dbooth 700: $all =~ s/\n(\<\;($namePattern)\>\;)\s*/\n\<\;$preUniq$2$postUniq\>\; /ig;
1.1 dbooth 701: # Change "speaker: ..." to "<b>speaker:<b> ..."
1.7 dbooth 702: $all =~ s/\n($speakerPattern)\:\s*/\n$preUniq$1\:$postUniq /ig;
1.1 dbooth 703: $all =~ s/$preUniq/$preSpeakerHTML/g;
704: $all =~ s/$postUniq/$postSpeakerHTML/g;
705:
1.7 dbooth 706: # Add <br /> before continuation lines:
707: $all =~ s/\n(\ *\.)/ <br \/>\n$1/g;
708: # Collapse multiple <br />s:
709: $all =~ s/<br \/>((\s*<br \/>)+)/<br \/>/g;
710: # Standardize continuation lines:
711: # $all =~ s/\n\s*\.+/\n\.\.\./g;
712: # Make links:
713: $all =~ s/(http\:([^\)\]\}\<\>\s\"\']+))/<a href=\"$1\">$1<\/a>/g;
714:
715: # Put into template:
716: # $all =~ s/\A\s*<\/p>//;
717: # $all .= "\n<\/p>\n";
718: my $presentAttendees = join(", ", @present);
719: my $regrets = join(", ", @regrets);
1.1 dbooth 720:
1.5 dbooth 721: my $result = $template;
1.8 dbooth 722: $result =~ s/SV_MEETING_DAY/$day0/g;
723: $result =~ s/SV_MEETING_MONTH_ALPHA/$monthAlpha/g;
724: $result =~ s/SV_MEETING_YEAR/$year/g;
725: $result =~ s/SV_MEETING_MONTH_NUMERIC/$mon0/g;
726: $result =~ s/SV_PREVIOUS_MEETING_URL/$previousURL/g;
727: $result =~ s/SV_MEETING_CHAIR/$chair/g;
728: $result =~ s/SV_MEETING_SCRIBE/$scribeName/g;
729: $result =~ s/SV_MEETING_AGENDA/$agenda/g;
730: $result =~ s/SV_TEAM_PAGE_LOCATION/SV_TEAM_PAGE_LOCATION/g;
731:
732: $result =~ s/SV_REGRETS/$regrets/g;
733: $result =~ s/SV_PRESENT_ATTENDEES/$presentAttendees/g;
1.21 dbooth 734: if ($result !~ s/SV_ACTION_ITEMS/$formattedActions/)
735: {
736: if ($result =~ s/SV_NEW_ACTION_ITEMS/$formattedActions/)
737: { warn "WARNING: Template format has changed. SV_NEW_ACTION_ITEMS should now be SV_ACTION_ITEMS\n"; }
738: else { warn "WARNING: SV_ACTION_ITEMS marker not found in template!\n"; }
739: }
1.8 dbooth 740: $result =~ s/SV_AGENDA_BODIES/$all/;
741: $result =~ s/SV_MEETING_TITLE/$title/g;
1.1 dbooth 742:
1.8 dbooth 743: my $formattedLogURL = '<p>See also: <a href="SV_MEETING_IRC_URL">IRC log</a></p>';
744: if ($logURL eq "SV_MEETING_IRC_URL")
1.1 dbooth 745: {
746: warn "**** Missing IRC LOG!!!! ****\n";
747: $formattedLogURL = "";
748: }
749: $formattedLogURL = "" if $logURL =~ m/\ANone\Z/i;
1.8 dbooth 750: $result =~ s/SV_FORMATTED_IRC_URL/$formattedLogURL/g;
751: $result =~ s/SV_MEETING_IRC_URL/$logURL/g;
1.1 dbooth 752:
1.7 dbooth 753:
754: print $result;
1.5 dbooth 755: exit 0;
1.7 dbooth 756:
757: ##################################################################
758: ########################## NormalizerMircTxt #########################
759: ##################################################################
760: # Format from saving MIRC buffer.
761: sub NormalizerMircTxt
762: {
763: die if @_ != 1;
764: my ($all) = @_;
1.8 dbooth 765: # Join continued lines:
766: $all =~ s/\n\ \ //g;
767: # Fix split URLs:
768: # <RalphS> -> http://lists.w3.org/Archives/Team/w3t-mit/2002Mar/00
769: # 46.html Simon's two minutes
770: # while ($all =~ s/(http\:[^\ ]+)\n\ \ /$1/ig) {}
771: # while ($all =~ s/(http\:[^\ ]+)\n\ /$1/ig) {}
772: # Count the number of recognized lines
1.7 dbooth 773: my @lines = split(/\n/, $all);
774: my $n = 0;
775: my $namePattern = '([\\w\\-]([\\w\\d\\-]*))';
776: foreach my $line (@lines)
777: {
1.8 dbooth 778: # * unlogged comment
779: if ($line =~ m/\A\s*\*\s/) { $n++; }
1.7 dbooth 780: # <ericn> Discussion on how to progress
1.8 dbooth 781: elsif ($line =~ m/\A\<$namePattern\>\s/) { $n++; }
1.7 dbooth 782: # warn "LINE: $line\n";
783: }
784: # warn "NormalizerMircTxt n matches: $n\n";
785: my $score = $n / @lines;
786: return($score, $all);
787: }
788:
789: ##################################################################
1.8 dbooth 790: ########################## NormalizerRRSAgentText #########################
1.7 dbooth 791: ##################################################################
792: # Example: http://www.w3.org/2003/03/03-ws-desc-irc.txt
1.8 dbooth 793: sub NormalizerRRSAgentText
1.7 dbooth 794: {
795: die if @_ != 1;
796: my ($all) = @_;
1.8 dbooth 797: # Join continued lines:
798: $all =~ s/\n\ \ //g;
799: # Count the number of recognized lines
1.7 dbooth 800: my @lines = split(/\n/, $all);
801: my $n = 0;
802: my $namePattern = '([\\w\\-]([\\w\\d\\-]*))';
803: my $timePattern = '((\s|\d)\d\:(\s|\d)\d\:(\s|\d)\d)';
804: foreach my $line (@lines)
805: {
806: # 20:41:27 <ericn> Review of minutes
807: $n++ if $line =~ s/\A$timePattern\s+(\<$namePattern\>\s)/$5/;
808: # warn "LINE: $line\n";
809: }
1.9 dbooth 810: $all = join("\n", @lines);
1.8 dbooth 811: # warn "NormalizerRRSAgentText n matches: $n\n";
1.7 dbooth 812: my $score = $n / @lines;
813: return($score, $all);
814: }
815:
816: ##################################################################
817: ########################## NormalizerRRSAgentHtml #########################
818: ##################################################################
819: # Example: http://www.w3.org/2003/03/03-ws-desc-irc.html
820: sub NormalizerRRSAgentHtml
821: {
822: die if @_ != 1;
823: my ($all) = @_;
824: my @lines = split(/\n/, $all);
825: my $n = 0;
826: my $namePattern = '([\\w\\-]([\\w\\d\\-]*))';
827: my $timePattern = '((\s|\d)\d\:(\s|\d)\d\:(\s|\d)\d)';
828: foreach my $line (@lines)
829: {
830: # <dt id="T14-35-34">14:35:34 [scribe]</dt><dd>Gudge: why not sufficient?</dd>
831: $n++ if $line =~ s/\A\<dt\s+id\=\"($namePattern)\"\>$timePattern\s+\[($namePattern)\]\<\/dt\>\s*\<dd\>(.*)\<\/dd\>\s*\Z/\<$8\> $11/;
832: # warn "LINE: $line\n";
833: }
834: $all = join("\n", @lines);
835: # warn "NormalizerRRSAgentHtml n matches: $n\n";
836: my $score = $n / @lines;
837: # Unescape &entity;
838: $all =~ s/\&\;/\&/g;
839: $all =~ s/\<\;/\</g;
840: $all =~ s/\>\;/\>/g;
841: $all =~ s/\"\;/\"/g;
842: return($score, $all);
843: }
844:
845: ##################################################################
846: ########################## NormalizerRRSAgentHTMLText #########################
847: ##################################################################
848: # This is for the format that is displayed in the browser from HTML.
849: # I.e., when you display the HTML in a browser, and then copy and paste
850: # the text from the browser window.
851: sub NormalizerRRSAgentHTMLText
852: {
853: die if @_ != 1;
854: my ($all) = @_;
855: my $n = 0;
856: my $namePattern = '([\\w\\-]([\\w\\d\\-]*))';
857: my $timePattern = '((\s|\d)\d\:(\s|\d)\d\:(\s|\d)\d)';
858: my $done = "";
859: while($all =~ s/\A((.*\n)(.*\n))//) # Grab next two lines
860: {
861: my $linePair = $1;
862: my $line1 = $2;
863: my $line2 = $3;
864: # This format uses line pairs:
865: # 14:43:30 [Arthur]
866: # If it's abstract, it goes into portType
867: if ($linePair =~ s/\A($timePattern)\s+\[($namePattern)\][\ \t]*\n/\<$6\> /)
868: {
869: $n++;
870: # warn "LINE: $line\n";
871: $done .= $linePair;
872: }
873: else {
874: $done .= $line1;
875: $all = $line2 . $all;
876: }
877: }
878: $done .= $all;
879: $all = $done;
880: # warn "NormalizerRRSAgentHTMLText n matches: $n\n";
881: my @lines = split(/\n/, $all);
882: my $score = $n / @lines;
883: return($score, $all);
884: }
885:
886: ##################################################################
887: ########################## NormalizerYahoo #########################
888: ##################################################################
889: sub NormalizerYahoo
890: {
891: die if @_ != 1;
892: my ($all) = @_;
893: my @lines = split(/\n/, $all);
894: my $n = 0;
895: my $namePattern = '([\\w\\-]([\\w\\d\\-]*))';
896: foreach my $line (@lines)
897: {
898: $n++ if $line =~ s/\A($namePattern)\:\s/\<$1\> /;
899: # warn "LINE: $line\n";
900: }
901: $all = join("\n", @lines);
902: # warn "NormalizerYahoo n matches: $n\n";
903: my $score = $n / @lines;
904: return($score, $all);
905: }
906:
1.5 dbooth 907: ##################################################################
1.20 dbooth 908: ########################## NormalizerPlainText #########################
909: ##################################################################
910: # This is just a plain text file of notes made by the scribe.
911: # This format does NOT use timestamps, nor does it use <speakerName>
912: # at the beginning of each line. It does still use the "dbooth: ..."
913: # convention to indicate what someone said.
914: sub NormalizerPlainText
915: {
916: die if @_ != 1;
917: my ($all) = @_;
918: # Join continued lines:
919: # Count the number of recognized lines
920: my @lines = split(/\n/, $all);
921: my $n = 0;
922: my $timePattern = '((\s|\d)\d\:(\s|\d)\d\:(\s|\d)\d)';
923: my $namePattern = '([\\w\\-]([\\w\\d\\-]*))';
924: for (my $i=0; $i<@lines; $i++)
925: {
926: # Lines should NOT have timestamps:
927: # 20:41:27 <ericn> Review of minutes
928: next if $lines[$i] =~ m/\A$timePattern\s+/;
929: # Lines should NOT start with <speakerName>:
930: # <ericn> Review of minutes
931: next if $lines[$i] =~ m/\A(\<$namePattern\>\s)/;
932: # warn "LINE: $lines[$i]\n";
933: $n++;
934: }
935: # Now add "<scribe> " to the beginning of each line, to make it like
936: # the standard format.
937: for (my $i=0; $i<@lines; $i++)
938: {
939: $lines[$i] = "<scribe> " . $lines[$i];
940: }
941: $all = join("\n", @lines);
942: # warn "NormalizerPlainText n matches: $n\n";
943: my $score = $n / @lines;
944: return($score, $all);
945: }
946:
947: ##################################################################
1.7 dbooth 948: ##################### GetTemplate ####################
1.5 dbooth 949: ##################################################################
1.7 dbooth 950: sub GetTemplate
951: {
1.1 dbooth 952: @_ == 1 || die;
953: my ($templateFile) = @_;
1.7 dbooth 954: open($templateFile,"<$templateFile") || return "";
955: my $template = join("",<$templateFile>);
1.1 dbooth 956: $template =~ s/\r//g;
1.7 dbooth 957: close($templateFile);
958: return $template;
959: }
960:
1.5 dbooth 961: ##################################################################
1.7 dbooth 962: ######################## GetDate ####################
1.5 dbooth 963: ##################################################################
1.10 dbooth 964: # Grab date from $all or IRC log name or default to today's date.
1.7 dbooth 965: sub GetDate
966: {
1.10 dbooth 967: @_ == 3 || die;
968: my ($all, $namePattern, $logURL) = @_;
1.7 dbooth 969: my @days = qw(Sun Mon Tue Wed Thu Fri Sat);
970: @days == 7 || die;
971: my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
972: @months == 12 || die;
1.1 dbooth 973: my %monthNumbers = map {($months[$_], $_+1)} (0 .. 11);
974: # warn "GetDate monthNumbers: ",join(" ",%monthNumbers),"\n";
975: my @date = ();
976: # Look for Date: 12 Sep 2002
1.7 dbooth 977: if ($all =~ s/\n\<$namePattern\>\s*(Date)\s*\:\s*(.*)\n/\n/i)
1.1 dbooth 978: {
979: # Parse date from input.
980: # I should have used a library function for this, but I wrote
981: # this without net access, so I couldn't get one.
982: my $d = $4;
983: $d =~ s/\A\s+//;
984: $d =~ s/\s+\Z//;
985: warn "Found Date: $d\n";
986: my @words = split(/\s+/, $d);
987: die "ERROR: Date not understood: $d\n" if @words != 3;
988: my ($mday, $tmon, $year) = @words;
989: exists($monthNumbers{$tmon}) || die;
990: my $mon = $monthNumbers{$tmon};
1.7 dbooth 991: ($mon > 0 && $mon < 13) || die;
992: ($mday > 0 && $mday < 32) || die;
1.1 dbooth 993: ($year > 2000 && $year < 2100) || die;
1.7 dbooth 994: my $day0 = sprintf("%0d", $mday);
995: my $mon0 = sprintf("%0d", $mon);
1.1 dbooth 996: @date = ($day0, $mon0, $year, $tmon);
997: }
1.10 dbooth 998: # Figure out date from IRC log name:
999: elsif ($logURL =~ m/\Ahttp\:\/\/(www\.)?w3\.org\/(\d+)\/(\d+)\/(\d+).+\-irc/)
1000: {
1001: my $year = $2;
1002: my $mon = $3;
1003: my $mday = $4;
1004: ($mon > 0 && $mon < 13) || die;
1005: ($year > 2000 && $year < 2100) || die;
1006: ($mday > 0 && $mday < 32) || die;
1007: my $day0 = sprintf("%0d", $mday);
1008: my $mon0 = sprintf("%0d", $mon);
1009: @date = ($day0, $mon0, $year, $months[$mon-1]);
1010: warn "Got date from IRC log name: $day0 " . $months[$mon-1] . " $year\n";
1011: }
1.1 dbooth 1012: else
1013: {
1.20 dbooth 1014: warn "WARNING: No date found! Assuming today. (Hint: Specify\n";
1015: warn "the IRC log, and the date will be determined from that.)\n";
1016: warn "Or specify the date like this:\n";
1017: warn "<dbooth> Date: 12 Sep 2002\n\n";
1.1 dbooth 1018: # Assume today's date by default.
1.7 dbooth 1019: my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
1020: $mon++; # put in range [1..12] instead of [0..11].
1021: ($mon > 0 && $mon < 13) || die;
1022: $year += 1900;
1.1 dbooth 1023: ($year > 2000 && $year < 2100) || die;
1.7 dbooth 1024: ($mday > 0 && $mday < 32) || die;
1025: my $day0 = sprintf("%0d", $mday);
1026: my $mon0 = sprintf("%0d", $mon);
1.1 dbooth 1027: @date = ($day0, $mon0, $year, $months[$mon-1]);
1028: }
1029: # warn "GetDate Returning date info: @date\n";
1.20 dbooth 1030: return @date;
1.7 dbooth 1031: }
1032:
1.1 dbooth 1033:
1034:
1.5 dbooth 1035: ##################################################################
1.7 dbooth 1036: ###################### GetNames ######################
1.5 dbooth 1037: ##################################################################
1.7 dbooth 1038: # Look for people in IRC log.
1039: sub GetNames
1040: {
1041: @_ == 2 || die;
1042: my($all, $scribe) = @_;
1043:
1044: # Some important data/constants:
1045: my @rooms = qw(MIT308 SophiaSofa DISA);
1.1 dbooth 1046:
1.20 dbooth 1047: my @stopList = qw(a q on Re items Zakim Topic muted and agenda Regrets http the
1.17 dbooth 1048: RRSAgent Loggy Zakim2 ACTION Chair Meeting DONE PENDING WITHDRAWN
1049: Scribe 00AM 00PM P IRC Topics Keio DROPPED ger-logger
1.3 dbooth 1050: yes no abstain Consensus Participants Question RESOLVED strategy
1.17 dbooth 1051: AGREED Date speaker queue no one in XachBot got it WARNING);
1.1 dbooth 1052: @stopList = (@stopList, @rooms);
1.7 dbooth 1053: @stopList = map {tr/A-Z/a-z/; $_} @stopList; # Make stopList lower case
1.1 dbooth 1054: my %stopList = map {($_,$_)} @stopList;
1055:
1.7 dbooth 1056: my %synonyms = ();
1057: %synonyms = qw(
1058: alan-home Alan
1059: amymtg Amy
1060: caribou Carine
1061: Chaals Charles
1062: chaalsGVA Charles
1063: chaalsNCE Charles
1064: Dave DaveRaggett
1065: DaveR DaveRaggett
1066: DaveRagget DaveRaggett
1067: dbooth dbooth
1068: David dbooth
1069: DB dbooth
1070: DavidB dbooth
1071: danbri DanBri
1072: danc_ DanC
1073: danc DanC
1074: dand DanielD
1075: EM EricM
1076: Eric EricM
1077: ericP-WA EricP
1078: ericP-air EricP
1079: ger Gerald
1.1 dbooth 1080: HT Henry
1081: HH Hugo
1.7 dbooth 1082: hugo Hugo
1083: ivan Ivan
1.1 dbooth 1084: janSeaTac Janet
1.7 dbooth 1085: karl Karl
1086: reagle-tu JosephR
1087: reagleMIT JosephR
1088: Joseph JosephR
1089: judy Judy
1.1 dbooth 1090: MaxF MaxF
1.7 dbooth 1091: MCF Marie-Claire
1092: MC Marie-Claire
1093: marie Marie-Claire
1094: mari Marisol
1095: MSM MichaelSM
1096: MSMbot MichaelSM
1097: Michael MichaelSM
1.1 dbooth 1098: MJDuesrst Martin
1099: olivier Olivier
1.7 dbooth 1100: plh Philippe
1101: plh-sjc Philippe
1102: Ralph RalphS
1.1 dbooth 1103: rigo Rigo
1104: sandro Sandro
1.7 dbooth 1105: sim Simon
1106: simHOME Simon
1107: Hernandez Simon
1.1 dbooth 1108: SB Steve
1.7 dbooth 1109: SusanL SusanLesch
1110: Ted Ted
1111: Tim TimBL
1.1 dbooth 1112: VQ VincentQ
1.7 dbooth 1113: ) if $useTeamSynonyms;
1114: foreach my $n (values %synonyms)
1115: {
1116: $synonyms{$n} = $n; # Make TimBL --> TimBL
1117: }
1118:
1119: # Easier pattern matching:
1120: $all = "\n" . $all . "\n";
1.1 dbooth 1121:
1.7 dbooth 1122: # Now start collecting names.
1123: my %names = ();
1124: my $t; # Temp
1125:
1126: # ...something.html Simon's two minutes
1127: $t = $all;
1.1 dbooth 1128: my $namePattern = '([\\w\\-]([\\w\\d\\-]*))';
1129: # warn "namePattern: $namePattern\n";
1.7 dbooth 1130: while($t =~ s/\b($namePattern)\'s\s+(2|two)\s+ minutes/ /)
1131: {
1132: my $n = $1;
1133: $names{$n} = $n;
1134: }
1135:
1136: # <dbooth> MC: I have integrated most of the coments i received
1137: $t = $all;
1138: while($t =~ s/\n\<((\w|\-)+)\>(\ +)((\w|\-)+)\:/\n/i)
1139: {
1140: my $n = $4;
1141: next if exists($names{$n});
1142: # warn "Matched # <dbooth> $n" . ": ...\n";
1143: $names{$n} = $n;
1144: }
1.1 dbooth 1145: # warn "names: ",join(" ",keys %names),"\n";
1.7 dbooth 1146:
1147: # <Steven> Hello
1148: $t = $all;
1149: while($t =~ s/\n\<((\w|\-)+)\>/\n/)
1150: {
1151: my $n = $1;
1152: next if exists($names{$n});
1153: # warn "Matched # <$n>\n";
1154: $names{$n} = $n;
1.1 dbooth 1155: # warn "Found name: $n\n";
1.7 dbooth 1156: }
1.1 dbooth 1157:
1158: # Zakim sees 4 items remaining on the agenda
1.7 dbooth 1159: $t = $all;
1.1 dbooth 1160: while ($t =~ s/\n\s*((\<Zakim\>)|(\*\s*Zakim\s)).*\b(agenda|agendum)\b.*\n/\n/)
1161: {
1162: my $match = $&;
1163: $match =~ s/\A\s+//;
1164: $match =~ s/\s+\Z//;
1165: # warn "DELETED: $match\n";
1166: }
1167:
1168: # <Zakim> I see no one on the speaker queue
1169: # <Zakim> I see Hugo, Yves, Philippe on the speaker queue
1.7 dbooth 1170: # <Zakim> I see MIT308, Ivan, Marie-Claire, Steven, Janet, EricM
1.17 dbooth 1171: # <Zakim> On the phone I see Joseph, m3mSEA, MIT308, Marja
1172: # <Zakim> On IRC I see Nobu, SusanL, RRSAgent, ht, Ian, ericP
1173: # <Zakim> ... simonMIT, XachBot
1.7 dbooth 1174: # <Zakim> I see MIT308, Ivan, Marie-Claire, Steven, Janet, EricM
1.17 dbooth 1175: # <Zakim> MIT308 has Martin, Ted, Ralph, Alan, EricP, Vivien
1176: # <Zakim> +Carine, Yves, Hugo; got it
1177: #
1178: # The stopList will later eliminate "no one" or "on the speaker queue",
1179: # so we don't need to worry about them here.
1180: while($t =~ s/\n\<Zakim\>\s+((([\w\d\_][\w\d\_\-]+) has\s+)|(I see\s+)|(On the phone I see\s+)|(On IRC I see\s+)|(\.\.\.\s+)|(\+))(.*)\n/\n/)
1.7 dbooth 1181: {
1.17 dbooth 1182: my $list = $9;
1.1 dbooth 1183: $list =~ s/\A\s+//;
1184: $list =~ s/\s+\Z//;
1.7 dbooth 1185: my @names = split(/[^\w\-]+/, $list);
1186: @names = map {s/\A\s+//; s/\s+\Z//; $_} @names;
1187: @names = grep {$_} @names;
1188: # warn "Matched # <Zakim> I see: @names\n";
1189: foreach my $n (@names)
1190: {
1191: next if exists($names{$n});
1192: $names{$n} = $n;
1193: }
1194: }
1195:
1196: # Make the keys all lower case, so that they'll match:
1197: %synonyms = map {my $oldn = $_; tr/A-Z/a-z/; ($_, $synonyms{$oldn})} keys %synonyms;
1198: %names = map {my $oldn = $_; tr/A-Z/a-z/; ($_, $names{$oldn})} keys %names;
1199: # warn "Lower case name keys:\n";
1200: foreach my $n (sort keys %names)
1201: {
1202: # warn " $n $names{$n}\n";
1203: }
1204:
1205: # Map synonyms to standardize spellings and expand abbreviations.
1206: %names = map {
1207: exists($synonyms{$_})
1208: ? ($_, $synonyms{$_})
1209: : ($_, $names{$_})
1210: } keys %names;
1211: # At this point different keys may map to the same value.
1212: # warn "After applying synonyms:\n";
1213: foreach my $n (keys %names)
1214: {
1215: # warn " $n $names{$n}\n";
1216: }
1.1 dbooth 1217:
1218: # Eliminate non-names
1.7 dbooth 1219: foreach my $n (keys %names)
1220: {
1.1 dbooth 1221: # Filter out names in stopList
1222: if (exists($stopList{$n})) { delete $names{$n}; }
1223: # Filter out names less than two chars in length:
1224: elsif (length($n) < 2) { delete $names{$n}; }
1225: # Filter out names not starting with a letter
1226: elsif ($names{$n} !~ m/\A[a-zA-Z]/) { delete $names{$n}; }
1.7 dbooth 1227: }
1.1 dbooth 1228:
1.7 dbooth 1229: # Make a list of unique names for the attendee list:
1230: my %uniqNames = ();
1231: foreach my $n (values %names)
1232: {
1233: $uniqNames{$n} = $n;
1234: }
1.1 dbooth 1235:
1236: # Make a list of all names seen (all variations) in lower case:
1237: my %allNames = ();
1238: foreach my $n (%names, %synonyms)
1239: {
1240: my $name = $n;
1241: $name =~ tr/A-Z/a-z/;
1242: $allNames{$name} = $name;
1243: }
1244: @allNames = sort keys %allNames;
1245: # warn "allNames: @allNames\n";
1246: my @allNameRefs = map { \$_ } @allNames;
1247:
1.7 dbooth 1248: # Canonicalize (normalize) the names in the IRC:
1249: my $expandedIRC = $all;
1250: my $nExpanded = 0;
1251: foreach my $n (keys %synonyms)
1252: {
1.1 dbooth 1253: next if !$canonicalizeNames;
1.7 dbooth 1254: my $v = $synonyms{$n};
1255: next if $v eq $n;
1256: my $qn = quotemeta($n);
1257: if ($expandedIRC =~ s/([^\w\-])($qn)([^\w\-])/$1$v$3/ig)
1258: {
1259: $nExpanded++;
1260: # warn "============ START ============\n";
1261: # warn " $expandedIRC\n";
1262: # warn "============ STOP ============\n";
1263: }
1264: }
1265: # warn "nExpanded: $nExpanded\n";
1266:
1.1 dbooth 1267: my $lcScribe = $scribe;
1.7 dbooth 1268: $lcScribe =~ tr/A-Z/a-z/;
1269: $scribe = $synonyms{$lcScribe} if exists($synonyms{$lcScribe});
1270: my @sortedUniqNames = sort values %uniqNames;
1271: return($expandedIRC, $scribe, \@allNameRefs, @sortedUniqNames);
1272: }
1.1 dbooth 1273:
1.5 dbooth 1274: ##################################################################
1.1 dbooth 1275: ################ DefaultTemplate ####################
1.5 dbooth 1276: ##################################################################
1.1 dbooth 1277: sub DefaultTemplate
1278: {
1.5 dbooth 1279: return &PublicTemplate();
1280: }
1281:
1282: ##################################################################
1283: ####################### SampleInput ##############################
1284: ##################################################################
1285: sub SampleInput
1286: {
1287: my $sampleInput = <<'SampleInput-EOF'
1.7 dbooth 1288: <dbooth> Scribe: dbooth
1289: <dbooth> Chair: Jonathan
1290: <dbooth> Meeting: Weekly Baking Club Meeting
1.5 dbooth 1291: <dbooth> Date: 05 Dec 2002
1292: <dbooth> Topic: Review of Action Items
1.7 dbooth 1293: <Philippe> PENDING ACTION: Barbara to bake 3 pies
1.8 dbooth 1294: <Philippe> ----
1.7 dbooth 1295: <Philippe> DONE ACTION: David to make ice cream
1.20 dbooth 1296: <Philippe> ACTION: David to make frosting -- DONE
1297: <Philippe> ACTION: David to make candles *DONE*
1298: <Philippe> ACTION: David to make world peace *PENDING*
1.5 dbooth 1299: <dbooth> Topic: What to Eat for Dessert
1.7 dbooth 1300: <dbooth> Joseph: I think that we should all eat cake
1301: <dbooth> ... with ice creme.
1.5 dbooth 1302: <dbooth> s/creme/cream/
1303: <Philippe> That's a good idea
1304: <dbooth> ACTION: dbooth to send a message to himself about action items
1305: <dbooth> Topic: Next Week's Meeting
1306: <Philippe> I think we should do this again next week.
1307: <Jonathan> Sounds good to me.
1308: <dbooth> rrsagent, where am i?
1309: <RRSAgent> I am logging.
1.7 dbooth 1310: <RRSAgent> See http://www.w3.org/2002/11/07-ws-arch-irc#T13-59-36
1.5 dbooth 1311: SampleInput-EOF
1312: ;
1313: return $sampleInput;
1314: }
1315:
1316: ##################################################################
1317: ###################### PublicTemplate ############################
1318: ##################################################################
1319: sub PublicTemplate
1320: {
1321: my $template = <<'PublicTemplate-EOF'
1.16 dbooth 1322: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1.7 dbooth 1323: <html>
1324: <head>
1.8 dbooth 1325: <title>SV_MEETING_TITLE -- SV_MEETING_DAY SV_MEETING_MONTH_ALPHA SV_MEETING_YEAR</title>
1.7 dbooth 1326: <LINK rel="STYLESHEET" href="http://www.w3.org/StyleSheets/base.css">
1327: <LINK rel="STYLESHEET" href="http://www.w3.org/StyleSheets/public.css">
1.8 dbooth 1328: <meta content="SV_MEETING_TITLE" lang="en" name="Title">
1.7 dbooth 1329: <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
1330: </head>
1331:
1332: <body>
1333: <p><a href="http://www.w3.org/"><img src="http://www.w3.org/Icons/WWW/w3c_home" alt="W3C" border="0"
1.1 dbooth 1334: height="48" width="72"></a>
1335:
1.7 dbooth 1336: </p>
1337:
1.8 dbooth 1338: <h1>SV_MEETING_TITLE<br>
1339: SV_MEETING_DAY SV_MEETING_MONTH_ALPHA SV_MEETING_YEAR</h1>
1.7 dbooth 1340:
1.1 dbooth 1341: <!-- Old:
1.8 dbooth 1342: <p>See also: <a href="SV_MEETING_IRC_URL">IRC log</a></p>
1.1 dbooth 1343: -->
1.8 dbooth 1344: SV_FORMATTED_IRC_URL
1.7 dbooth 1345:
1346: <h2><a name="attendees">Attendees</a></h2>
1347:
1348: <div class="intro">
1.8 dbooth 1349: <p>Present: SV_PRESENT_ATTENDEES</p>
1350: <p>Regrets: SV_REGRETS</p>
1351: <p>Chair: SV_MEETING_CHAIR </p>
1352: <p>Scribe: SV_MEETING_SCRIBE</p>
1.7 dbooth 1353: </div>
1354:
1355: <h2>Contents</h2>
1356: <ul>
1.11 dbooth 1357: <li><a href="#agenda">Topics</a>
1.7 dbooth 1358: <ol>
1.8 dbooth 1359: SV_MEETING_AGENDA
1.7 dbooth 1360: </ol>
1361: </li>
1362: <li><a href="#newActions">Summary of Action Items</a></li>
1363: </ul>
1364: <hr>
1365:
1366:
1.1 dbooth 1367: <!-- We don't need the agenda items listed twice.
1.11 dbooth 1368: <h2><a name="agenda">Topics</a></h2>
1.7 dbooth 1369: <ul>
1.8 dbooth 1370: SV_MEETING_AGENDA
1.7 dbooth 1371: </ul>
1.1 dbooth 1372: -->
1.7 dbooth 1373:
1.8 dbooth 1374: SV_AGENDA_BODIES
1.7 dbooth 1375: <!--
1.15 hugo 1376: <h3 id="item1">Item name (owner)</h3>
1.7 dbooth 1377: <p>... text of discussion ...</p>
1378:
1.15 hugo 1379: <h3 id="item2">Item name (owner)</h3>
1.7 dbooth 1380: <p>... text of discussion ...</p>
1381: -->
1382:
1383:
1384: <h2><a name="newActions">Summary of Action Items</a></h2>
1.21 dbooth 1385: <!-- Action Items -->
1386: SV_ACTION_ITEMS
1.7 dbooth 1387:
1388: <hr>
1389:
1390: <address>
1.1 dbooth 1391: <!--
1.7 dbooth 1392: <a href="http://validator.w3.org/check/referer"><img border="0"
1393: src="http://validator.w3.org/images/vh40.gif" alt="Valid HTML 4.0!"
1394: height="31" width="88" align="right">
1395: </a>
1.1 dbooth 1396: -->
1.8 dbooth 1397: <!-- <a href="/Team/SV_TEAM_PAGE_LOCATION">David Booth</a> <br /> -->
1.6 dbooth 1398: Minutes formatted by David Booth's perl script:
1.7 dbooth 1399: <a href="http://dev.w3.org/cvsweb/~checkout~/2002/scribe/">http://dev.w3.org/cvsweb/~checkout~/2002/scribe/</a><br>
1.20 dbooth 1400: $Date: 2003/06/13 21:02:20 $
1.7 dbooth 1401: </address>
1402: </body>
1403: </html>
1.5 dbooth 1404: PublicTemplate-EOF
1405: ;
1406: return $template;
1407: }
1408:
1409: ##################################################################
1410: ###################### MemberTemplate ############################
1411: ##################################################################
1412: sub MemberTemplate
1413: {
1414: my $template = <<'MemberTemplate-EOF'
1.16 dbooth 1415: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1.7 dbooth 1416: <html>
1417: <head>
1.8 dbooth 1418: <title>SV_MEETING_TITLE -- SV_MEETING_DAY SV_MEETING_MONTH_ALPHA SV_MEETING_YEAR</title>
1.7 dbooth 1419: <LINK rel="STYLESHEET" href="http://www.w3.org/StyleSheets/base.css">
1420: <LINK rel="STYLESHEET" href="http://www.w3.org/StyleSheets/member.css">
1421: <link rel="STYLESHEET" href="http://www.w3.org/StyleSheets/member-minutes.css">
1.8 dbooth 1422: <meta content="SV_MEETING_TITLE" lang="en" name="Title">
1.7 dbooth 1423: <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
1424: </head>
1425:
1426: <body>
1427: <p><a href="http://www.w3.org/"><img src="http://www.w3.org/Icons/WWW/w3c_home" alt="W3C" border="0"
1.5 dbooth 1428: height="48" width="72"></a>
1.7 dbooth 1429: </p>
1430:
1.8 dbooth 1431: <h1>SV_MEETING_TITLE<br>
1432: SV_MEETING_DAY SV_MEETING_MONTH_ALPHA SV_MEETING_YEAR</h1>
1.7 dbooth 1433:
1.5 dbooth 1434: <!-- Old:
1.8 dbooth 1435: <p>See also: <a href="SV_MEETING_IRC_URL">IRC log</a></p>
1.5 dbooth 1436: -->
1.8 dbooth 1437: SV_FORMATTED_IRC_URL
1.7 dbooth 1438:
1439: <h2><a name="attendees">Attendees</a></h2>
1440:
1441: <div class="intro">
1.8 dbooth 1442: <p>Present: SV_PRESENT_ATTENDEES</p>
1443: <p>Regrets: SV_REGRETS</p>
1444: <p>Chair: SV_MEETING_CHAIR </p>
1445: <p>Scribe: SV_MEETING_SCRIBE</p>
1.7 dbooth 1446: </div>
1447:
1448: <h2>Contents</h2>
1449: <ul>
1.11 dbooth 1450: <li><a href="#agenda">Topics</a>
1.7 dbooth 1451: <ol>
1.8 dbooth 1452: SV_MEETING_AGENDA
1.7 dbooth 1453: </ol>
1454: </li>
1455: <li><a href="#newActions">Summary of Action Items</a></li>
1456: </ul>
1457: <hr>
1458:
1459:
1.5 dbooth 1460: <!-- We don't need the agenda items listed twice.
1.11 dbooth 1461: <h2><a name="agenda">Topics</a></h2>
1.7 dbooth 1462: <ul>
1.8 dbooth 1463: SV_MEETING_AGENDA
1.7 dbooth 1464: </ul>
1465: -->
1466:
1.8 dbooth 1467: SV_AGENDA_BODIES
1.7 dbooth 1468: <!--
1.15 hugo 1469: <h3 id="item1">Item name (owner)</h3>
1.7 dbooth 1470: <p>... text of discussion ...</p>
1471:
1.15 hugo 1472: <h3 id="item2">Item name (owner)</h3>
1.7 dbooth 1473: <p>... text of discussion ...</p>
1.5 dbooth 1474: -->
1.7 dbooth 1475:
1476:
1477: <h2><a name="newActions">Summary of Action Items</a></h2>
1.5 dbooth 1478: <!-- Done Action Items -->
1.8 dbooth 1479: SV_DONE_ACTION_ITEMS
1.5 dbooth 1480: <!-- Pending Action Items -->
1.8 dbooth 1481: SV_PENDING_ACTION_ITEMS
1.5 dbooth 1482: <!-- New Action Items -->
1.21 dbooth 1483: SV_ACTION_ITEMS
1.7 dbooth 1484:
1485: <hr>
1486:
1487: <address>
1.5 dbooth 1488: <!--
1.7 dbooth 1489: <a href="http://validator.w3.org/check/referer"><img border="0"
1490: src="http://validator.w3.org/images/vh40.gif" alt="Valid HTML 4.0!"
1491: height="31" width="88" align="right">
1492: </a>
1.5 dbooth 1493: -->
1.8 dbooth 1494: <!-- <a href="/Team/SV_TEAM_PAGE_LOCATION">David Booth</a> <br /> -->
1.6 dbooth 1495: Minutes formatted by David Booth's perl script:
1.7 dbooth 1496: <a href="http://dev.w3.org/cvsweb/~checkout~/2002/scribe/">http://dev.w3.org/cvsweb/~checkout~/2002/scribe/</a><br>
1.20 dbooth 1497: $Date: 2003/06/13 21:02:20 $
1.7 dbooth 1498: </address>
1499: </body>
1500: </html>
1.5 dbooth 1501: MemberTemplate-EOF
1.1 dbooth 1502: ;
1.5 dbooth 1503: return $template;
1.1 dbooth 1504: }
1505:
1.5 dbooth 1506: ##################################################################
1507: ###################### TeamTemplate ############################
1508: ##################################################################
1509: sub TeamTemplate
1510: {
1511: my $template = <<'TeamTemplate-EOF'
1.16 dbooth 1512: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1.7 dbooth 1513: <html>
1514: <head>
1.8 dbooth 1515: <title>SV_MEETING_TITLE -- SV_MEETING_DAY SV_MEETING_MONTH_ALPHA SV_MEETING_YEAR</title>
1.7 dbooth 1516: <LINK rel="STYLESHEET" href="http://www.w3.org/StyleSheets/base.css">
1517: <LINK rel="STYLESHEET" href="http://www.w3.org/StyleSheets/team.css">
1518: <link rel="STYLESHEET" href="http://www.w3.org/StyleSheets/team-minutes.css">
1.8 dbooth 1519: <meta content="SV_MEETING_TITLE" lang="en" name="Title">
1.7 dbooth 1520: <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
1521: </head>
1522:
1523: <body>
1524: <p><a href="http://www.w3.org/"><img src="http://www.w3.org/Icons/WWW/w3c_home" alt="W3C" border="0"
1.5 dbooth 1525: height="48" width="72"></a>
1526:
1.7 dbooth 1527: </p>
1528:
1.8 dbooth 1529: <h1>SV_MEETING_TITLE<br>
1530: SV_MEETING_DAY SV_MEETING_MONTH_ALPHA SV_MEETING_YEAR</h1>
1.7 dbooth 1531:
1.5 dbooth 1532: <!-- Old:
1.8 dbooth 1533: <p>See also: <a href="SV_MEETING_IRC_URL">IRC log</a></p>
1.5 dbooth 1534: -->
1.8 dbooth 1535: SV_FORMATTED_IRC_URL
1.7 dbooth 1536:
1537: <h2><a name="attendees">Attendees</a></h2>
1538:
1539: <div class="intro">
1.8 dbooth 1540: <p>Present: SV_PRESENT_ATTENDEES</p>
1541: <p>Regrets: SV_REGRETS</p>
1542: <p>Chair: SV_MEETING_CHAIR </p>
1543: <p>Scribe: SV_MEETING_SCRIBE</p>
1.7 dbooth 1544: </div>
1545:
1546: <h2>Contents</h2>
1547: <ul>
1.11 dbooth 1548: <li><a href="#agenda">Topics</a>
1.7 dbooth 1549: <ol>
1.8 dbooth 1550: SV_MEETING_AGENDA
1.7 dbooth 1551: </ol>
1552: </li>
1553: <li><a href="#newActions">Summary of Action Items</a></li>
1554: </ul>
1555: <hr>
1556:
1557:
1.5 dbooth 1558: <!-- We don't need the agenda items listed twice.
1.11 dbooth 1559: <h2><a name="agenda">Topics</a></h2>
1.7 dbooth 1560: <ul>
1.8 dbooth 1561: SV_MEETING_AGENDA
1.7 dbooth 1562: </ul>
1.5 dbooth 1563: -->
1.7 dbooth 1564:
1.8 dbooth 1565: SV_AGENDA_BODIES
1.7 dbooth 1566: <!--
1.15 hugo 1567: <h3 id="item1">Item name (owner)</h3>
1.7 dbooth 1568: <p>... text of discussion ...</p>
1569:
1.15 hugo 1570: <h3 id="item2">Item name (owner)</h3>
1.7 dbooth 1571: <p>... text of discussion ...</p>
1572: -->
1573:
1574:
1575: <h2><a name="newActions">Summary of Action Items</a></h2>
1.5 dbooth 1576: <!-- Done Action Items -->
1.8 dbooth 1577: SV_DONE_ACTION_ITEMS
1.5 dbooth 1578: <!-- Pending Action Items -->
1.8 dbooth 1579: SV_PENDING_ACTION_ITEMS
1.5 dbooth 1580: <!-- New Action Items -->
1.21 dbooth 1581: SV_ACTION_ITEMS
1.7 dbooth 1582:
1583: <hr>
1584:
1585: <address>
1.5 dbooth 1586: <!--
1.7 dbooth 1587: <a href="http://validator.w3.org/check/referer"><img border="0"
1588: src="http://validator.w3.org/images/vh40.gif" alt="Valid HTML 4.0!"
1589: height="31" width="88" align="right">
1590: </a>
1.5 dbooth 1591: -->
1.8 dbooth 1592: <!-- <a href="/Team/SV_TEAM_PAGE_LOCATION">David Booth</a> <br /> -->
1.6 dbooth 1593: Minutes formatted by David Booth's perl script:
1.7 dbooth 1594: <a href="http://dev.w3.org/cvsweb/~checkout~/2002/scribe/">http://dev.w3.org/cvsweb/~checkout~/2002/scribe/</a><br>
1.20 dbooth 1595: $Date: 2003/06/13 21:02:20 $
1.7 dbooth 1596: </address>
1597: </body>
1598: </html>
1.5 dbooth 1599: TeamTemplate-EOF
1600: ;
1601: return $template;
1602: }
1603:
1604: ##################################################################
1605: ###################### MITTemplate ############################
1606: ##################################################################
1607: sub MITTemplate
1.1 dbooth 1608: {
1.5 dbooth 1609: my $template = <<'MITTemplate-EOF'
1.16 dbooth 1610: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
1.7 dbooth 1611: <html>
1612: <head>
1.8 dbooth 1613: <title>SV_MEETING_TITLE -- SV_MEETING_DAY SV_MEETING_MONTH_ALPHA SV_MEETING_YEAR</title>
1.7 dbooth 1614: <LINK rel="STYLESHEET" href="http://www.w3.org/StyleSheets/base.css">
1615: <LINK rel="STYLESHEET" href="http://www.w3.org/StyleSheets/team.css">
1616: <link rel="STYLESHEET" href="http://www.w3.org/StyleSheets/team-minutes.css">
1.8 dbooth 1617: <meta content="SV_MEETING_TITLE" lang="en" name="Title">
1.7 dbooth 1618: <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
1619: </head>
1620:
1621: <body>
1622: <p><a href="http://www.w3.org/"><img src="http://www.w3.org/Icons/WWW/w3c_home" alt="W3C" border="0"
1623: height="48" width="72"></a> <a href="http://www.w3.org/Team"><img width="48" height="48"
1624: alt="W3C Team home" border="0" src="http://www.w3.org/Icons/WWW/team"></a> | <a
1.8 dbooth 1625: href="http://www.w3.org/Team/Meeting/MIT-scribes">MIT Meetings</a> | <a href="http://www.w3.org/">SV_MEETING_MONTH_ALPHA
1626: SV_MEETING_YEAR</a></p>
1.7 dbooth 1627:
1.8 dbooth 1628: <h1>SV_MEETING_TITLE<br>
1629: SV_MEETING_DAY SV_MEETING_MONTH_ALPHA SV_MEETING_YEAR</h1>
1.7 dbooth 1630:
1.5 dbooth 1631: <!-- Old:
1.8 dbooth 1632: <p>See also: <a href="SV_MEETING_IRC_URL">IRC log</a></p>
1.5 dbooth 1633: -->
1.8 dbooth 1634: SV_FORMATTED_IRC_URL
1.7 dbooth 1635:
1636: <h2><a name="attendees">Attendees</a></h2>
1637:
1638: <div class="intro">
1.8 dbooth 1639: <p>Present: SV_PRESENT_ATTENDEES</p>
1640: <p>Regrets: SV_REGRETS</p>
1641: <p>Chair: SV_MEETING_CHAIR </p>
1642: <p>Scribe: SV_MEETING_SCRIBE</p>
1.7 dbooth 1643: </div>
1644:
1645: <h2>Contents</h2>
1646: <ul>
1.11 dbooth 1647: <li><a href="#agenda">Topics</a>
1.7 dbooth 1648: <ol>
1.8 dbooth 1649: SV_MEETING_AGENDA
1.7 dbooth 1650: </ol>
1651: </li>
1652: <li><a href="#newActions">Summary of Action Items</a></li>
1653: </ul>
1654: <hr>
1655:
1656:
1.5 dbooth 1657: <!-- We don't need the agenda items listed twice.
1.11 dbooth 1658: <h2><a name="agenda">Topics</a></h2>
1.7 dbooth 1659: <ul>
1.8 dbooth 1660: SV_MEETING_AGENDA
1.7 dbooth 1661: </ul>
1.5 dbooth 1662: -->
1.7 dbooth 1663:
1.8 dbooth 1664: SV_AGENDA_BODIES
1.7 dbooth 1665: <!--
1.15 hugo 1666: <h3 id="item1">Item name (owner)</h3>
1.7 dbooth 1667: <p>... text of discussion ...</p>
1668:
1.15 hugo 1669: <h3 id="item2">Item name (owner)</h3>
1.7 dbooth 1670: <p>... text of discussion ...</p>
1671: -->
1672:
1673:
1674: <h2><a name="newActions">Summary of Action Items</a></h2>
1.5 dbooth 1675: <!-- Done Action Items -->
1.8 dbooth 1676: SV_DONE_ACTION_ITEMS
1.5 dbooth 1677: <!-- Pending Action Items -->
1.8 dbooth 1678: SV_PENDING_ACTION_ITEMS
1.5 dbooth 1679: <!-- New Action Items -->
1.21 dbooth 1680: SV_ACTION_ITEMS
1.7 dbooth 1681:
1682: <hr>
1683:
1684: <address>
1.5 dbooth 1685: <!--
1.7 dbooth 1686: <a href="http://validator.w3.org/check/referer"><img border="0"
1687: src="http://validator.w3.org/images/vh40.gif" alt="Valid HTML 4.0!"
1688: height="31" width="88" align="right">
1689: </a>
1.5 dbooth 1690: -->
1.8 dbooth 1691: <!-- <a href="/Team/SV_TEAM_PAGE_LOCATION">David Booth</a> <br /> -->
1.6 dbooth 1692: Minutes formatted by David Booth's perl script:
1.7 dbooth 1693: <a href="http://dev.w3.org/cvsweb/~checkout~/2002/scribe/">http://dev.w3.org/cvsweb/~checkout~/2002/scribe/</a><br>
1.20 dbooth 1694: $Date: 2003/06/13 21:02:20 $
1.7 dbooth 1695: </address>
1696: </body>
1697: </html>
1.5 dbooth 1698: MITTemplate-EOF
1.1 dbooth 1699: ;
1.5 dbooth 1700: return $template;
1.1 dbooth 1701: }
1.5 dbooth 1702:
1.1 dbooth 1703:
Webmaster