<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">

<head>
<meta http-equiv=Content-Type content="text/html; charset=us-ascii">
<meta name=Generator content="Microsoft Word 12 (filtered medium)">
<style>
<!--
 /* Font Definitions */
 @font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
 /* Style Definitions */
 p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
span.EmailStyle17
        {mso-style-type:personal-compose;
        font-family:"Calibri","sans-serif";
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
-->
</style>
<!--[if gte mso 9]><xml>
 <o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
 <o:shapelayout v:ext="edit">
  <o:idmap v:ext="edit" data="1" />
 </o:shapelayout></xml><![endif]-->
</head>

<body lang=EN-US link=blue vlink=purple><!--ppd1000037--><!--ppd1000035-->

<div class=WordSection1>

<p class=MsoNormal>I've worked at a lot of places, even with people who
supposedly knew what they were doing. I appreciate the best practices model
described in this paper: <a
href="http://www.perforce.com/perforce/papers/bestpractices.html">http://www.perforce.com/perforce/papers/bestpractices.html</a><o:p></o:p></p>

<p class=MsoNormal><o:p> </o:p></p>

<p class=MsoNormal>I'd describe the difference between perforce and subversion
thusly: perforce lacks a decent "svn status" command but closely integrates
the concept of "changesets"  to its workflow. A changeset is
connected group of changes across one(uninterestingly) or more files
representing one feature or fix.<o:p></o:p></p>

<p class=MsoNormal><o:p> </o:p></p>

<p class=MsoNormal>So, here at my new company, I developed an integrated incident,
problem and change management system using RT and Subversion. I think it might
even work better with git, but that's how it goes, sometimes.<o:p></o:p></p>

<p class=MsoNormal><o:p> </o:p></p>

<p class=MsoNormal>Below is how I keep subversion changes tied into RT. Later,
tickets are released to QA and then production via their ticket number. By
using the mainline, rather than promotion, model, certain things remain
relatively sane over time. All commits go to the trunk branch, and please don't
commit anything that breaks anyone else's code. :)<o:p></o:p></p>

<p class=MsoNormal><o:p> </o:p></p>

<p class=MsoNormal>And, yes, I probably should have used placeholders and bind
variables. However, it isn't like the input is coming from complete strangers. <o:p></o:p></p>

<p class=MsoNormal><o:p> </o:p></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>#!/usr/bin/perl<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># if the file's
commit message includes a ticket #, add those tickets to RT<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># svn commit -m
"#123 these files get attached to ticket #123"<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># the id of the
'Files' customfield in the customfields table<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># yes, it could be a
subselect<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>our $customfield =
5;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>our $path_to_log =
"/path/to/file";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>use strict;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>use warnings;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>use DBI;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>use DBD::Pg;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>use Data::Dumper
qw(Dumper);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>use constant SVNLOOK
=> '/usr/bin/svnlook';<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># include BEGIN
block in your commit hooks<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># to prevent people
from getting funny and providing<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># their own versions
of perl libraries, especially<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># important if the
subversion post-commit user has<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># any privileges<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>BEGIN {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
pop @INC;    # removes .<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
@INC = grep { !m{^/home} } @INC;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>my $log = open_log($path_to_log);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>my ($repos, $rev) =
@ARGV;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>print $log
"Repo: $repos\nRev : $rev\n";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>my $dbh =
DBI->connect('dbi:Pg:dbname=rt3', 'rt_user', 'rt_pass');<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>print $log "Got
db connection\n";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>exit(1) unless my
($author, $ticket) = in_log_message($repos, $rev);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>print $log join
"\n", '-' x 80, "Author: $author\nTicket: $ticket", '';<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>exit(1) unless my
$rt_user_id = find_author_in_rt($dbh, $author);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>print $log "RT
User ID: $rt_user_id\n";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>my ($adds, $dels,
$mods) = find_changed_files($repos, $rev);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># maybe just a
property change, or something<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>exit unless %$adds
|| %$dels || %$mods;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>my ($old_row_id,
%files) = files_currently_in_ticket($dbh, $ticket);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>my $exit =
update_ticket(<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
$rev,    $dbh,  $old_row_id, $rt_user_id, $ticket,<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
\%files, $adds, $mods,       $dels<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>exit;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># nothing but subs<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>sub update_ticket {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my (<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
$rev,     $dbh,  $old_row_id, $rt_user_id, $ticket,<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
$current, $adds, $mods,       $dels<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    )
= @_;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
print $log Dumper(\@_);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my %files;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
foreach my $file (keys %$current) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
next if !$file or exists $dels->{$file};<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
$files{$file} = $current->{$file};<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    #
overwrite revision if modified<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
foreach my $file (keys %$adds, keys %$mods) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
next if !$file or exists $dels->{$file};<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
$files{$file} = $rev;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $raw = join "\n", map { $_ . '@' . $files{$_} } keys %files;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my ($content, $largecontent, $type, $encoding) =<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>     
length($raw) > 255<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>     
? ('', $raw, 'text/plain', 'none')<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>     
: ($raw, '', '', '');<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $query = "<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>      
insert into objectcustomfieldvalues(<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>        
customfield,objecttype,objectid,content,largecontent,contenttype,<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>         contentencoding,creator,created,lastupdatedBy,lastupdated<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>      
) values (<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>        
$customfield,'RT::Ticket',$ticket,'$content','$largecontent','$type',<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>        
'$encoding',$rt_user_id,now(),$rt_user_id,now()<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>      
)<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
print $log $query, "\n";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $sth = $dbh->prepare($query);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
$sth->execute() or die $sth->errstr;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
if ($old_row_id) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
my $update = "<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>        
update objectcustomfieldvalues<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>            
set disabled = 1<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>          
where id = $old_row_id<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
$sth = $dbh->prepare($update);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
my $rv = $sth->execute();<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
die $sth->errstr unless defined $rv;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>sub
files_currently_in_ticket {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my ($dbh, $ticket) = @_;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $sth = $dbh->prepare("<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>     
select id, content, contenttype, largecontent<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
from objectcustomfieldvalues<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>      
where objecttype  = 'RT::Ticket'<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>        
and objectid    = $ticket<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>        
and customfield = $customfield<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>        
and disabled    = 0<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
");<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
$sth->execute();<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
return 0 unless $sth->rows;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $row     = $sth->fetchrow_hashref();<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $content = $row->{largecontent} || $row->{content};<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $id      = $row->{id};<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
print $log "Content: $content\n";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my %files;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my @lines = grep /\S/, split /\n/, $content;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    #
some of this block relates to handling <o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    #
earlier versions of the commit hook<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
foreach my $line (@lines) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
$line =~ s/^\s*//;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
$line =~ s/\s*$//;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
next unless $line;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
if ($line =~ s/\@(\d+)//) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>           
$files{$line} = $1;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
} else {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>           
$files{$line} = '';<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
print $log Dumper(\%files);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
return 0 unless keys %files;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
return ($id, %files);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>sub in_log_message {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my ($repos, $rev) = @_;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my @svnlooklines = read_from_process(SVNLOOK, 'info', $repos, '-r', $rev);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $author = shift @svnlooklines;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
shift @svnlooklines for 1 .. 2;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $log = join "\n", @svnlooklines;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
if ($log =~ /\#(\d+)/) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
return ($author, $1);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
return;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>sub
find_author_in_rt {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my ($dbh, $author) = @_;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $sth = $dbh->prepare("select id from users where name =
'$author'");<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
$sth->execute();<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
return unless $sth->rows();<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $row = $sth->fetchrow_hashref();<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
return $row->{id};<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>sub
find_changed_files {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my ($repos, $rev) = @_;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my @svnlooklines =<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>     
read_from_process(SVNLOOK, 'changed', $repos, '-r', $rev);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    #
Parse the changed nodes.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my %adds;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my %dels;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my %mods;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
foreach my $line (@svnlooklines) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
my $path = '';<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
my $code = '';<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
# Split the line up into the modification code and path, ignoring<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
# property modifications.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
if ($line =~ /^(.).  (.*)$/) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>           
$code = $1;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>           
$path = $2;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
(my $subpath = $path) =~ s{^.*?/rosalind2/}{};<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
if ($code eq 'A') {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>           
$adds{$subpath}++;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
} elsif ($code eq 'D') {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>           
$dels{$subpath}++;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
} else {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>           
$mods{$subpath}++;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
return (\%adds, \%dels, \%mods);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>sub open_log {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $file = shift;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
umask 0002;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
open my $fh, ">>$file" or die "Coudln't open `$file':
$!";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
return $fh;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># the below is
copied from commit-email.pl from subversion<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># Start a child
process safely without using /bin/sh.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>sub
safe_read_from_pipe {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
unless (@_) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
croak "$0: safe_read_from_pipe passed no arguments.\n";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $pid = open(SAFE_READ, '-|');<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
unless (defined $pid) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
die "$0: cannot fork: $!\n";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
unless ($pid) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
open(STDERR, ">&STDOUT")<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>     
    or die "$0: cannot dup STDOUT: $!\n";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
exec(@_)<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>         
or die "$0: cannot exec `@_': $!\n";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my @output;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
while (<SAFE_READ>) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
s/[\r\n]+$//;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
push(@output, $_);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
close(SAFE_READ);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $result = $?;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    my
$exit   = $result >> 8;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $signal = $result & 127;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my $cd     = $result & 128 ? "with core dump"
: "";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
if ($signal or $cd) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
warn "$0: pipe from `@_' failed $cd: exit=$exit signal=$signal\n";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
if (wantarray) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
return ($result, @output);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }
else {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
return $result;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># Use
safe_read_from_pipe to start a child process safely and return<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># the output if it
succeeded or an error message followed by the output<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'># if it failed.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>sub read_from_process
{<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
unless (@_) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
croak "$0: read_from_process passed no arguments.\n";<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
my ($status, @output) = &safe_read_from_pipe(@_);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>   
if ($status) {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
return ("$0: `@_' failed with this output:", @output);<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }
else {<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>       
return @output;<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>    }<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'>}<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

<p class=MsoNormal><span style='font-family:"Courier New"'><o:p> </o:p></span></p>

</div>

<br /><br /><FONT size=2 face=Verdana><STRONG>Josh Narins</STRONG></FONT><BR><BR><FONT size=1 
face=Verdana>Director of Application Development<BR>SeniorBridge<BR>845 Third Ave<br/>
7th Floor<BR>New York, NY 10022 <br/>
Tel: (212) 994-6194 <br/>
Fax: (212) 994-4260 <br/>
Mobile: 
(917) 488-6248<BR>jnarins@seniorbridge.com<BR><A 
href="http://www.seniorbridge.com/">seniorbridge.com</A></FONT><BR><BR><IMG 
border=0 hspace=0 alt=SeniorBridge align=baseline 
src="http://www.seniorbridge.com/images/seniorbridgedisclaimerTAG.gif"></FONT><br /><br />
<HR style="HEIGHT: 1px">
<FONT size=1 face=Verdana><STRONG>SeniorBridge Statement of 
Confidentiality:</STRONG> The contents of this email message are intended for 
the exclusive use of the addressee(s) and may contain confidential or privileged 
information. Any dissemination, distribution or copying of this email by an 
unintended or mistaken recipient is strictly prohibited. In said event, kindly 
reply to the sender and destroy all entries of this message and any attachments 
from your system. Thank you.</FONT></body>

</html>