[Rt-commit] r3107 - in rt/branches/QUEBEC-EXPERIMENTAL: . html/Admin/Queues html/Elements html/Search lib/RT lib/RT/Action lib/RT/I18N lib/RT/Interface/Web lib/RT/Interface/Web/QueryBuilder lib/t/regression sbin

jesse at bestpractical.com jesse at bestpractical.com
Wed Jun 8 23:06:21 EDT 2005


Author: jesse
Date: Wed Jun  8 23:06:16 2005
New Revision: 3107

Added:
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Interface/Web/QueryBuilder/
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Interface/Web/QueryBuilder.pm   (contents, props changed)
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Interface/Web/QueryBuilder/Tree.pm   (contents, props changed)
   rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/21query-builder.t
Modified:
   rt/branches/QUEBEC-EXPERIMENTAL/   (props changed)
   rt/branches/QUEBEC-EXPERIMENTAL/html/Admin/Queues/Modify.html
   rt/branches/QUEBEC-EXPERIMENTAL/html/Elements/Error
   rt/branches/QUEBEC-EXPERIMENTAL/html/Search/Build.html
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Action/AutoOpen.pm
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/cs.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/da.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/de.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/es.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/fi.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/fr.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/he.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/hu.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/it.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/ja.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/nl.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/no.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/pl.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/pt_br.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/ru.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/zh_cn.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/zh_tw.po
   rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Transaction_Overlay.pm
   rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/02basic_web.t
   rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/04send_email.t
   rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/09record_cf_api.t
   rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/10merge.t
   rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/11-template-insert.t
   rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/12-search.t
   rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/13-attribute-tests.t
   rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/15cf_single_values_are_single.t
   rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/20savedsearch.t
   rt/branches/QUEBEC-EXPERIMENTAL/sbin/rt-test-dependencies.in
Log:
 r19664 at hualien:  jesse | 2005-06-08 18:41:46 -0400
  r19152 at hualien:  jesse | 2005-06-02 01:36:59 -0400
   r18763 at hualien (orig r2992):  kevinr | 2005-05-31 16:10:01 -0400
    r2965 at sad-girl-in-snow:  kevinr | 2005-05-25 17:47:26 -0400
    * changed "e-mail" back to "email"
    * removed discussion of pre-5.8.3 perl versions
   
   r18764 at hualien (orig r2993):  kevinr | 2005-05-31 16:10:33 -0400
    r2967 at sad-girl-in-snow:  kevinr | 2005-05-25 18:37:20 -0400
    * Added a comma where a compound sentence wanted it.
   
   r18765 at hualien (orig r2994):  kevinr | 2005-05-31 16:11:31 -0400
    r3004 at sad-girl-in-snow:  kevinr | 2005-05-31 15:52:19 -0400
    RT-Ticket: 6684
    RT-Status: resolve
    RT-Action: correspond
    
    html/Elements/Error should not continue, and has been changed to add the
    standard footer element on %cleanup.
   
   r18766 at hualien (orig r2995):  kevinr | 2005-05-31 20:34:40 -0400
    r3008 at SAD-GIRL-IN-SNOW:  kevinr | 2005-05-31 17:05:08 -0400
    RT-Ticket: 6423
    RT-Status: resolve
    RT-Action: correspond
    
    * Corrected a typo in Admin/Queues/Modify.html and propagated it to all the
    po files, as per Angelo Turetta's suggestion.
   
   r18767 at hualien (orig r2996):  kevinr | 2005-05-31 20:35:39 -0400
    r3009 at SAD-GIRL-IN-SNOW:  kevinr | 2005-05-31 17:52:48 -0400
    RT-Ticket: 6669
    RT-Status: resolved
    RT-Action: correspond
    
    * Fixed an extra space in lib/RT/Transaction_Overlay.pm and propagated the 
    change to the po files, as per Brandon Pulsipher's suggestion.
   
   r18768 at hualien (orig r2997):  kevinr | 2005-05-31 20:38:19 -0400
    r3010 at SAD-GIRL-IN-SNOW:  kevinr | 2005-05-31 18:10:17 -0400
    RT-Ticket: 6423
    RT-Status: resolve
    RT-Action: correspond
    
    * Fixed a line I broke in revision 3008 -- vi removed the '%1'.
   
   r18769 at hualien (orig r2998):  kevinr | 2005-05-31 21:08:40 -0400
    r3841 at SAD-GIRL-IN-SNOW:  kevinr | 2005-05-31 21:07:42 -0400
    RT-Ticket: 6669
    RT-Status: resolved
    RT-Action: correspond
    
    * Fixed the mysteriously-absent '1' in the Norwegian po.
   
   r18826 at hualien (orig r3039):  glasser | 2005-06-01 18:32:16 -0400
    r33100 at tin-foil:  glasser | 2005-05-25 20:21:43 -0400
    Mini refactoring of Tree->SQL/HTML function
   
   r18827 at hualien (orig r3040):  glasser | 2005-06-01 18:32:34 -0400
    r33101 at tin-foil:  glasser | 2005-05-25 21:05:02 -0400
    Attempt to add parentheses to the clauses select list, in Query Builder.
   
   r18828 at hualien (orig r3041):  glasser | 2005-06-01 18:33:51 -0400
    r33102 at tin-foil:  glasser | 2005-05-25 22:22:53 -0400
    build_array was being called twice for two totally disconnected reasons.  Split one out.
   
   r18829 at hualien (orig r3042):  glasser | 2005-06-01 18:34:38 -0400
    r33103 at tin-foil:  glasser | 2005-05-25 22:24:07 -0400
    And remove the old functionality too.
   
   r18830 at hualien (orig r3043):  glasser | 2005-06-01 18:34:56 -0400
    r33104 at tin-foil:  glasser | 2005-05-25 23:53:28 -0400
    Fix mistake in the function I just made
    
    Add a bit of testing of the query builder.
   
   r18831 at hualien (orig r3044):  glasser | 2005-06-01 18:35:14 -0400
    r33105 at tin-foil:  glasser | 2005-05-26 00:02:36 -0400
    Run 'make license-tag'
   
   r18832 at hualien (orig r3045):  glasser | 2005-06-01 18:35:33 -0400
    r33106 at tin-foil:  glasser | 2005-05-26 01:21:29 -0400
    Move stuff out from html/Search/Build.html into a module; refactor some of the code there.
   
   r18833 at hualien (orig r3046):  glasser | 2005-06-01 18:35:53 -0400
    r33107 at tin-foil:  glasser | 2005-05-26 01:56:25 -0400
    More Query Builder tree refactoring.
   
   r18834 at hualien (orig r3047):  glasser | 2005-06-01 18:36:24 -0400
    r33108 at tin-foil:  glasser | 2005-05-26 02:12:48 -0400
    rt-ticket: 6568
    rt-update: correspond
    
      * Better fix to Query Builder; in addition to refactoring most of the code which got
        information out of the tree, prune away childless AND/ORs, fixing the bug from ticket #6568.
    
    Also get rid of the reaction to the "Clear" action, which I don't think exists, and which 
    I think is incorrect, since the root is supposed to have one child (see where it is
    first created).
    
   
   r18835 at hualien (orig r3048):  glasser | 2005-06-01 18:36:40 -0400
    r33109 at tin-foil:  glasser | 2005-05-26 12:02:13 -0400
    More docs and refactoring on QueryBuilder::Tree
   
   r18836 at hualien (orig r3049):  glasser | 2005-06-01 18:36:55 -0400
    r33110 at tin-foil:  glasser | 2005-05-26 13:33:06 -0400
    Undo 'make license-tag' change; jesse should do this later though
   
   r18837 at hualien (orig r3050):  glasser | 2005-06-01 18:37:12 -0400
   
   r18838 at hualien (orig r3051):  glasser | 2005-06-01 18:37:29 -0400
    r33242 at tin-foil:  glasser | 2005-05-27 14:08:19 -0400
    * Improved Query builder Tests
    * add plans to a bunch of other tests
   
   r18839 at hualien (orig r3052):  glasser | 2005-06-01 18:37:45 -0400
    r33243 at tin-foil:  glasser | 2005-05-27 17:08:38 -0400
    Add some hopefully correct comments to the head of Search/Build
   
   r18840 at hualien (orig r3053):  glasser | 2005-06-01 18:38:05 -0400
    r33652 at tin-foil:  glasser | 2005-06-01 15:02:58 -0400
    A mini rewrite of testdeps: now it tells you at the bottom if it is missing anything
   
   r18841 at hualien (orig r3054):  glasser | 2005-06-01 18:38:38 -0400
    r33653 at tin-foil:  glasser | 2005-06-01 15:19:20 -0400
    fixdeps wasn't working for me (it was trying to detar inside my MiniCPAN!);
    its code was "correct" but presumably one of the other 500 modules that were
    loaded confused CPAN.  (This bug happened both before and after the previous change.)
    Now just uses a system() call to install.
   
   r18842 at hualien (orig r3055):  glasser | 2005-06-01 18:39:12 -0400
    r33654 at tin-foil:  glasser | 2005-06-01 16:36:18 -0400
    Fix some test plans, mark some QB tests TODO
   
   r18843 at hualien (orig r3056):  glasser | 2005-06-01 18:39:36 -0400
   
   r18844 at hualien (orig r3057):  robert | 2005-06-02 00:15:13 -0400
    r3073 at bear:  rspier | 2005-06-02T04:14:40.726890Z
    Support for RT-Control: no-autoopen 
    
   
  
 


Modified: rt/branches/QUEBEC-EXPERIMENTAL/html/Admin/Queues/Modify.html
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/html/Admin/Queues/Modify.html	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/html/Admin/Queues/Modify.html	Wed Jun  8 23:06:16 2005
@@ -72,13 +72,13 @@
 <&|/l&>Reply Address</&>:
 </TD><TD>
 <INPUT name="CorrespondAddress" value="<% ($Create) ? "" : $QueueObj->CorrespondAddress %>">
-<BR><font size="-1"><i><&|/l , $RT::CorrespondAddress&>(If left blank, will default to [_1]</&></i></font>
+<BR><font size="-1"><i><&|/l , $RT::CorrespondAddress&>(If left blank, will default to [_1])</&></i></font>
 </TD>
 <TD ALIGN=RIGHT>
 
 <&|/l&>Comment Address</&>: </TD><TD>
 <INPUT NAME="CommentAddress" value="<% ($Create) ? "" : $QueueObj->CommentAddress %>">
-<BR><font size="-1"><i><&|/l , $RT::CommentAddress&>(If left blank, will default to [_1]</&></i></font>
+<BR><font size="-1"><i><&|/l , $RT::CommentAddress&>(If left blank, will default to [_1])</&></i></font>
 </TD>
 </TR><TR>
 

Modified: rt/branches/QUEBEC-EXPERIMENTAL/html/Elements/Error
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/html/Elements/Error	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/html/Elements/Error	Wed Jun  8 23:06:16 2005
@@ -53,9 +53,11 @@
 <%$Details%>
 </font>
 <& /Elements/TitleBoxEnd &>
-</body>
-</HTML>
 
+<%cleanup>
+$m->comp('/Elements/Footer');
+$m->abort();
+</%cleanup>
 
 <%args>
 $Code => undef

Modified: rt/branches/QUEBEC-EXPERIMENTAL/html/Search/Build.html
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/html/Search/Build.html	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/html/Search/Build.html	Wed Jun  8 23:06:16 2005
@@ -43,6 +43,26 @@
 %# those contributions and any derivatives thereof.
 %# 
 %# END BPS TAGGED BLOCK }}}
+%#
+%# Data flow here:
+%#   The page receives a Query from the previous page, and maybe arguments
+%#   corresponding to actions.  (If it doesn't get a Query argument, it pulls
+%#   one out of the session hash.  Also, it could be getting just a raw query from
+%#   Build/Edit.html (Advanced).)
+%#
+%#   After doing some stuff with default arguments and saved searches, the ParseQuery
+%#   function (which is similar to, but not the same as, _parser in RT/Tickets_Overlay_SQL)
+%#   converts the Query into a RT::Interface::Web::QueryBuilder::Tree.  This mason file
+%#   then adds stuff to or modifies the tree based on the actions that had been requested
+%#   by clicking buttons.  It then calls GetQueryAndOptionList on the tree to generate
+%#   the SQL query (which is saved as a hidden input) and the option list for the Clauses
+%#   box in the top right corner.
+%#
+%#   Worthwhile refactoring: the tree manipulation code for the actions could use some cleaning
+%#   up.  The node-adding code is different in the "add" actions from in ParseQuery, which leads
+%#   to things like ParseQuery correctly not quoting numbers in numerical fields, while the "add"
+%#   action does quote it (this breaks SQLite).
+%#
 <& /Elements/Header, Title => $title &>
 <& /Ticket/Elements/Tabs, 
     current_tab => "Search/Build.html".$QueryString, 
@@ -61,7 +81,7 @@
 <table width=100% border="0" cellpadding="5">
 <tr valign="top">
 <td class="boxcontainer" rowspan="2" width="65%">
-<& Elements/PickCriteria, query => $Query, cfqueues => \%queues &>
+<& Elements/PickCriteria, query => $Query, cfqueues => $queues &>
 <& /Elements/Submit, Caption => loc('Add these terms to your search'), Label => loc('Add'), Name => 'AddClause'&>
 </td>
 
@@ -93,7 +113,8 @@
 </FORM>
 
 <%INIT>
-use Tree::Simple;
+use RT::Interface::Web::QueryBuilder;
+use RT::Interface::Web::QueryBuilder::Tree;
 
 my $search_hash = {};
 my $search;
@@ -157,7 +178,6 @@
 # }}}
 
 my @actions = ();
-my %queues;
 
 # Clean unwanted junk from the format
 $Format = $m->comp( '/Elements/ScrubHTML', Content => $Format ) if ($Format);
@@ -223,13 +243,9 @@
     $m->abort();
 }
 
-my @options;
-my $optionlist;
 $Query  = "";
-%queues = ();
 
-# Build the optionlist from the tree, so we can do additions and movements based on it
-$optionlist = build_array( \$Query, \@clauses, $tree, \@options, \%queues );
+my @options = $tree->GetDisplayedNodes;
 
 my @current_values = grep { defined } @options[@clauses];
 
@@ -296,7 +312,7 @@
                 Value => $value
             };
 
-            my $newnode = Tree::Simple->new($clause);
+            my $newnode = RT::Interface::Web::QueryBuilder::Tree->new($clause);
             if (@current_values) {
                 foreach my $value (@current_values) {
                     my $newindex = $value->getIndex() + 1;
@@ -386,7 +402,7 @@
                 my $sibling = $parent->getChild( $index - 1 );
                 if ( ref( $sibling->getNodeValue ) ) {
                     $parent->removeChild($value);
-                    my $newtree = Tree::Simple->new( 'AND', $parent );
+                    my $newtree = RT::Interface::Web::QueryBuilder::Tree->new( 'AND', $parent );
                     $newtree->addChild($value);
                 }
                 else {
@@ -396,7 +412,7 @@
             }
             else {
                 $parent->removeChild($value);
-                $newparent = Tree::Simple->new( 'AND', $parent );
+                $newparent = RT::Interface::Web::QueryBuilder::Tree->new( 'AND', $parent );
                 $newparent->addChild($value);
             }
         }
@@ -431,99 +447,23 @@
         push( @actions, [ loc("error: nothing to toggle"), -1 ] );
     }
 }
-elsif ( $ARGS{"Clear"} ) {
-    $tree = Tree::Simple->new( Tree::Simple->ROOT );
-}
+
+$tree->PruneChildlessAggregators;
 
 # }}}
 
 # {{{ Rebuild $Query based on the additions / movements
 $Query      = "";
- at options    = ();
-%queues     = ();
-$optionlist =
-  build_array( \$Query, \@current_values, $tree, \@options, \%queues );
-
-sub build_array {
-    my $Query      = shift;
-    my $values_ref = shift;
-    my $tree       = shift;
-    my ( $keys, $queues ) = @_;
-    my $i = 0;
-    my $optionlist;
-    my $depth = 0;
-    my %parens;
-
-    $tree->traverse(
-        sub {
-            my ($_tree) = @_;
-
-            return if $_tree->getParent->isRoot();
-
-            push @$keys, $_tree;
-            my $clause = $_tree->getNodeValue();
-            my $str;
-            my $ea = $_tree->getParent()->getNodeValue();
-            if ( ref($clause) ) {
-                $str .= $ea . " " if $_tree->getIndex() > 0;
-                $str .=
-                  $clause->{Key} . " " . $clause->{Op} . " " . $clause->{Value};
-
-                if ( $clause->{Key} eq "Queue" ) {
-                    $queues->{ $clause->{Value} } = 1;
-                }
-            }
-            else {
-                $str = $ea if $_tree->getIndex() > 0;
-            }
-
-            my $selected;
-            if ( grep { $_ == $_tree } @$values_ref ) {
-                $selected = "SELECTED";
-            }
-            else {
-                $selected = "";
-            }
-
-            foreach my $p ( keys %parens ) {
-                if ( $p > $_tree->getDepth ) {
-                    $$Query .= ')' x $parens{$p};
-                    $parens{$p}--;
-                }
-            }
-
-            $optionlist .=
-                "<option value=$i $selected>"
-              . ( "&nbsp;" x 5 x ( $_tree->getDepth() - 1 ) )
-              . $m->interp->apply_escapes( $str, 'h' )
-              . "</option>\n";
-            my $parent = $_tree->getParent();
-            if (   !( $parent->isRoot || $parent->getParent()->isRoot )
-                && !ref( $parent->getNodeValue() ) )
-            {
-                if ( $_tree->getIndex() == 0 ) {
-                    $$Query .= '(';
-                    $parens{ $_tree->getDepth }++;
-                }
-            }
-            $$Query .= " " . $str . " ";
-
-            if ( $_tree->getDepth < $depth ) {
-                $$Query .= ')';
-                $parens{$depth}--;
-            }
+my $optionlist_arrayref;
 
-            $i++;
-        }
-    );
+($Query, $optionlist_arrayref) = $tree->GetQueryAndOptionList(\@current_values);
+  
+my $optionlist = join "\n", map { qq(<option value="$_->{INDEX}" $_->{SELECTED}>) 
+                                  . ("&nbsp;" x (5 * $_->{DEPTH}))
+                                  . $m->interp->apply_escapes($_->{TEXT}, 'h') . qq(</option>) } @$optionlist_arrayref;
 
-    foreach my $p ( keys %parens ) {
-        $$Query .= ") " x $parens{$p};
-    }
 
-    return $optionlist;
 
-}
 
 use Regexp::Common qw /delimited/;
 
@@ -544,8 +484,8 @@
     my $depth = 1;
 
     # make a tree root
-    $$tree = Tree::Simple->new( Tree::Simple->ROOT );
-    my $root       = Tree::Simple->new( 'AND', $$tree );
+    $$tree = RT::Interface::Web::QueryBuilder::Tree->new;
+    my $root       = RT::Interface::Web::QueryBuilder::Tree->new( 'AND', $$tree );
     my $lastnode   = $root;
     my $parentnode = $root;
 
@@ -618,7 +558,7 @@
                 $depth++;
 
                 # make a new node that the clauses can be children of
-                $parentnode = Tree::Simple->new( $ea, $parentnode );
+                $parentnode = RT::Interface::Web::QueryBuilder::Tree->new( $ea, $parentnode );
             }
             else {
                 $depth--;
@@ -686,7 +626,7 @@
             };
 
             # explicity add a child to it
-            $lastnode = Tree::Simple->new( $clause, $parentnode );
+            $lastnode = RT::Interface::Web::QueryBuilder::Tree->new( $clause, $parentnode );
             $lastnode->getParent()->setNodeValue($ea);
 
             ( $ea, $key, $op, $value ) = ( "", "", "", "" );
@@ -725,11 +665,13 @@
 
 # }}}
 
+my $queues = $tree->GetReferencedQueues;
+
 # {{{ Deal with format changes
 my ( $AvailableColumns, $CurrentFormat );
 ( $Format, $AvailableColumns, $CurrentFormat ) = $m->comp(
     'Elements/BuildFormatString',
-    cfqueues => \%queues,
+    cfqueues => $queues,
     %ARGS, Format => $Format
 );
 

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Action/AutoOpen.pm
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Action/AutoOpen.pm	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Action/AutoOpen.pm	Wed Jun  8 23:06:16 2005
@@ -74,6 +74,8 @@
     if ( ( $self->TicketObj->Status eq 'open' )
          || ( ( $self->TicketObj->Status eq 'new' )
               && $self->TransactionObj->IsInbound )
+         || ( defined $self->TransactionObj->Message->First
+              && $self->TransactionObj->Message->First->GetHeader('RT-Control') =~ /\bno-autoopen\b/i )
       ) {
 
         return undef;

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/cs.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/cs.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/cs.po	Wed Jun  8 23:06:16 2005
@@ -351,7 +351,7 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
+msgid "(If left blank, will default to %1)"
 msgstr "(Pro prázdné pole se použije %1)"
 
 #: html/Admin/Elements/EditCustomFields:74 html/Admin/Elements/ListGlobalCustomFields:53
@@ -4567,8 +4567,8 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
-msgstr "Vzato %1 "
+msgid "Stolen from %1"
+msgstr "Vzato %1"
 
 #: html/Search/Elements/EditFormat:81
 msgid "Style"

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/da.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/da.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/da.po	Wed Jun  8 23:06:16 2005
@@ -354,8 +354,8 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
-msgstr "(Hvis ikke angivet vil defaulte til %1"
+msgid "(If left blank, will default to %1)"
+msgstr "(Hvis ikke angivet vil defaulte til %1)"
 
 #: html/Admin/Elements/EditCustomFields:74 html/Admin/Elements/ListGlobalCustomFields:53
 msgid "(No custom fields)"
@@ -4629,7 +4629,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "Stjålet fra %1"
 
 #: html/Search/Elements/EditFormat:81

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/de.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/de.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/de.po	Wed Jun  8 23:06:16 2005
@@ -3615,8 +3615,8 @@
 
 #. ($Old->Name)
 #: lib/RT/Transaction_Overlay.pm:619
-msgid "Stolen from %1 "
-msgstr "Gestohlen von %1 "
+msgid "Stolen from %1"
+msgstr "Gestohlen von %1"
 
 #: html/Elements/QuickCreate:52 html/Elements/SelectAttachmentField:47
 #: html/Search/Bulk.html:154 html/SelfService/Create.html:79
@@ -4913,7 +4913,7 @@
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
-msgid "(If left blank, will default to %1"
+msgid "(If left blank, will default to %1)"
 msgstr "(Standardwert: %1)"
 
 #: html/Admin/Elements/EditCustomFields:74
@@ -8554,8 +8554,8 @@
 
 #. ($Old->Name)
 #: lib/RT/Transaction_Overlay.pm:619
-msgid "Stolen from %1 "
-msgstr "Gestohlen von %1 "
+msgid "Stolen from %1"
+msgstr "Gestohlen von %1"
 
 #: html/Elements/QuickCreate:52 html/Elements/SelectAttachmentField:47
 #: html/Search/Bulk.html:154 html/SelfService/Create.html:79

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/es.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/es.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/es.po	Wed Jun  8 23:06:16 2005
@@ -377,8 +377,8 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
-msgstr "(Si se deja vacio, pasara por defecto a %1"
+msgid "(If left blank, will default to %1)"
+msgstr "(Si se deja vacio, pasara por defecto a %1)"
 
 #: NOT FOUND IN SOURCE
 msgid "(No Value)"
@@ -4817,7 +4817,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "Robado de %1"
 
 #: html/Search/Elements/EditFormat:81

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/fi.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/fi.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/fi.po	Wed Jun  8 23:06:16 2005
@@ -362,7 +362,7 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
+msgid "(If left blank, will default to %1)"
 msgstr "(Jos jätetään tyhjäksi, palaa arvoon %1)"
 
 #: NOT FOUND IN SOURCE
@@ -4597,7 +4597,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "Kaapattu käyttäjältä %1"
 
 #: html/Search/Elements/EditFormat:81

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/fr.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/fr.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/fr.po	Wed Jun  8 23:06:16 2005
@@ -379,8 +379,8 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
-msgstr "Si laissé à blanc, valeur par défaut : %1"
+msgid "(If left blank, will default to %1)"
+msgstr "(Si laissé à blanc, valeur par défaut : %1)"
 
 #: NOT FOUND IN SOURCE
 msgid "(No Value)"
@@ -4910,7 +4910,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "Volé à %1"
 
 #: html/Search/Elements/EditFormat:81

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/he.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/he.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/he.po	Wed Jun  8 23:06:16 2005
@@ -302,7 +302,7 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
+msgid "(If left blank, will default to %1)"
 msgstr ""
 
 #: html/Admin/Elements/EditCustomFields:74 html/Admin/Elements/ListGlobalCustomFields:53
@@ -3941,7 +3941,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "נגנב מ %1"
 
 #: html/Search/Elements/EditFormat:81

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/hu.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/hu.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/hu.po	Wed Jun  8 23:06:16 2005
@@ -268,7 +268,7 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
+msgid "(If left blank, will default to %1)"
 msgstr "(Ha üresen marad: %1)"
 
 #: html/Admin/Elements/EditCustomFields:74 html/Admin/Elements/ListGlobalCustomFields:53
@@ -3743,7 +3743,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "Probléma elcsenése %1 tulajdonostól"
 
 #: html/Search/Elements/EditFormat:81

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/it.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/it.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/it.po	Wed Jun  8 23:06:16 2005
@@ -110,7 +110,7 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
+msgid "(If left blank, will default to %1)"
 msgstr "(se non specificato usa: %1)"
 
 #: NOT FOUND IN SOURCE
@@ -4637,8 +4637,8 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
-msgstr "Sottratto da %1 "
+msgid "Stolen from %1"
+msgstr "Sottratto da %1"
 
 #: html/Search/Elements/EditFormat:81
 msgid "Style"
@@ -6248,7 +6248,7 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
+msgid "(If left blank, will default to %1)"
 msgstr "(se non specificato usa: %1)"
 
 #: NOT FOUND IN SOURCE
@@ -10807,8 +10807,8 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
-msgstr "Sottratto da %1 "
+msgid "Stolen from %1"
+msgstr "Sottratto da %1"
 
 #: html/Search/Elements/EditFormat:81
 msgid "Style"

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/ja.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/ja.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/ja.po	Wed Jun  8 23:06:16 2005
@@ -346,7 +346,7 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
+msgid "(If left blank, will default to %1)"
 msgstr ""
 
 #: html/Admin/Elements/EditCustomFields:74 html/Admin/Elements/ListGlobalCustomFields:53
@@ -4397,7 +4397,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "%1から盗用した"
 
 #: html/Search/Elements/EditFormat:81

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/nl.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/nl.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/nl.po	Wed Jun  8 23:06:16 2005
@@ -348,8 +348,8 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
-msgstr "(Indien leeggelaten, wordt voorzien van %1"
+msgid "(If left blank, will default to %1)"
+msgstr "(Indien leeggelaten, wordt voorzien van %1)"
 
 #: NOT FOUND IN SOURCE
 msgid "(No Value)"
@@ -4611,7 +4611,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "Gestolen van %1"
 
 #: html/Search/Elements/EditFormat:81

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/no.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/no.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/no.po	Wed Jun  8 23:06:16 2005
@@ -380,7 +380,7 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
+msgid "(If left blank, will default to %1)"
 msgstr "(Settes til standard %1 hvis blank)"
 
 #: NOT FOUND IN SOURCE
@@ -4887,8 +4887,8 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
-msgstr "Stjålet fra %1 "
+msgid "Stolen from %1"
+msgstr "Stjålet fra %1"
 
 #: html/Search/Elements/EditFormat:81
 msgid "Style"

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/pl.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/pl.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/pl.po	Wed Jun  8 23:06:16 2005
@@ -386,8 +386,8 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
-msgstr "(Jeśli pozostawisz puste, domyślnie zostanie ustawione na %1"
+msgid "(If left blank, will default to %1)"
+msgstr "(Jeśli pozostawisz puste, domyślnie zostanie ustawione na %1)"
 
 #: NOT FOUND IN SOURCE
 msgid "(No Value)"
@@ -5112,7 +5112,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "Przejęte od %1"
 
 #: html/Search/Elements/EditFormat:81

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/pt_br.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/pt_br.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/pt_br.po	Wed Jun  8 23:06:16 2005
@@ -377,8 +377,8 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
-msgstr "(Se deixado em branco, será entendido como %1"
+msgid "(If left blank, will default to %1)"
+msgstr "(Se deixado em branco, será entendido como %)"
 
 #: NOT FOUND IN SOURCE
 msgid "(No Value)"
@@ -4860,8 +4860,8 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
-msgstr "Roubado de %1 "
+msgid "Stolen from %1"
+msgstr "Roubado de %1"
 
 #: html/Search/Elements/EditFormat:81
 msgid "Style"

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/ru.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/ru.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/ru.po	Wed Jun  8 23:06:16 2005
@@ -368,8 +368,8 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
-msgstr "(Если пустое, то по-умолчанию равно %1"
+msgid "(If left blank, will default to %1)"
+msgstr "(Если пустое, то по-умолчанию равно %1)"
 
 #: NOT FOUND IN SOURCE
 msgid "(No Value)"
@@ -4960,7 +4960,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "Ответственный переназначен с %1"
 
 #: html/Search/Elements/EditFormat:81

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/zh_cn.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/zh_cn.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/zh_cn.po	Wed Jun  8 23:06:16 2005
@@ -405,7 +405,7 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
+msgid "(If left blank, will default to %1)"
 msgstr "(如果留白, 则预设为 %1)"
 
 #: NOT FOUND IN SOURCE
@@ -6376,7 +6376,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "承办人从 %1 强制更换"
 
 #: html/Search/Elements/EditFormat:81

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/zh_tw.po
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/zh_tw.po	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/I18N/zh_tw.po	Wed Jun  8 23:06:16 2005
@@ -405,7 +405,7 @@
 #: html/Admin/Queues/Modify.html:75 html/Admin/Queues/Modify.html:81
 #. ($RT::CorrespondAddress)
 #. ($RT::CommentAddress)
-msgid "(If left blank, will default to %1"
+msgid "(If left blank, will default to %1)"
 msgstr "(如果留白, 則預設為 %1)"
 
 #: NOT FOUND IN SOURCE
@@ -6376,7 +6376,7 @@
 
 #: lib/RT/Transaction_Overlay.pm.orig:665 lib/RT/Transaction_Overlay.pm:665
 #. ($Old->Name)
-msgid "Stolen from %1 "
+msgid "Stolen from %1"
 msgstr "承辦人從 %1 強制更換"
 
 #: html/Search/Elements/EditFormat:81

Added: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Interface/Web/QueryBuilder.pm
==============================================================================
--- (empty file)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Interface/Web/QueryBuilder.pm	Wed Jun  8 23:06:16 2005
@@ -0,0 +1,56 @@
+# BEGIN BPS TAGGED BLOCK {{{
+# 
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC 
+#                                          <jesse at bestpractical.com>
+# 
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
+# 
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+# 
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# 
+# 
+# CONTRIBUTION SUBMISSION POLICY:
+# 
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+# 
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+# 
+# END BPS TAGGED BLOCK }}}
+package RT::Interface::Web::QueryBuilder;
+
+use strict;
+use warnings;
+
+eval "require RT::Interface::Web::QueryBuilder_Vendor";
+die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/Web/QueryBuilder_Vendor.pm});
+eval "require RT::Interface::Web::QueryBuilder_Local";
+die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/Web/QueryBuilder_Local.pm});
+
+1;

Added: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Interface/Web/QueryBuilder/Tree.pm
==============================================================================
--- (empty file)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Interface/Web/QueryBuilder/Tree.pm	Wed Jun  8 23:06:16 2005
@@ -0,0 +1,245 @@
+# BEGIN BPS TAGGED BLOCK {{{
+# 
+# COPYRIGHT:
+#  
+# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC 
+#                                          <jesse at bestpractical.com>
+# 
+# (Except where explicitly superseded by other copyright notices)
+# 
+# 
+# LICENSE:
+# 
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+# 
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+# 
+# 
+# CONTRIBUTION SUBMISSION POLICY:
+# 
+# (The following paragraph is not intended to limit the rights granted
+# to you to modify and distribute this software under the terms of
+# the GNU General Public License and is only of importance to you if
+# you choose to contribute your changes and enhancements to the
+# community by submitting them to Best Practical Solutions, LLC.)
+# 
+# By intentionally submitting any modifications, corrections or
+# derivatives to this work, or any other work intended for use with
+# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+# you are the copyright holder for those contributions and you grant
+# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
+# royalty-free, perpetual, license to use, copy, create derivative
+# works based on those contributions, and sublicense and distribute
+# those contributions and any derivatives thereof.
+# 
+# END BPS TAGGED BLOCK }}}
+package RT::Interface::Web::QueryBuilder::Tree;
+
+use strict;
+use warnings;
+
+use base qw/Tree::Simple/;
+
+=head1 NAME
+
+  RT::Interface::Web::QueryBuilder::Tree - subclass of Tree::Simple used in Query Builder
+
+=head1 DESCRIPTION
+
+This class provides support functionality for the Query Builder (Search/Build.html).
+It is a subclass of L<Tree::Simple>.
+
+=head1 METHODS
+
+=head2 TraversePrePost PREFUNC POSTFUNC
+
+Traverses the tree depth-first.  Before processing the node's children,
+calls PREFUNC with the node as its argument; after processing all of the
+children, calls POSTFUNC with the node as its argument.
+
+(Note that unlike Tree::Simple's C<traverse>, it actually calls its functions
+on the root node passed to it.)
+
+=cut
+
+sub TraversePrePost {
+   my ($self, $prefunc, $postfunc) = @_;
+
+   $prefunc->($self);
+   
+   foreach my $child ($self->getAllChildren()) { 
+           $child->TraversePrePost($prefunc, $postfunc);
+   }
+   
+   $postfunc->($self);
+}
+
+=head2 GetReferencedQueues
+
+Returns a hash reference with keys each queue name referenced in a clause in
+the key (even if it's "Queue != 'Foo'"), and values all 1.
+
+=cut
+
+sub GetReferencedQueues {
+    my $self = shift;
+
+    my $queues = {};
+
+    $self->traverse(
+        sub {
+            my $node = shift;
+
+            return if $node->isRoot;
+
+            my $clause = $node->getNodeValue();
+         
+            if ( ref($clause) and $clause->{Key} eq 'Queue' ) {
+                $queues->{ $clause->{Value} } = 1;
+            };
+        }
+    );
+
+    return $queues;
+}
+
+=head2 GetQueryAndOptionList SELECTED_NODES
+
+Given an array reference of tree nodes that have been selected by the user,
+traverses the tree and returns the equivalent SQL query and a list of hashes
+representing the "clauses" select option list.  Each has contains the keys
+TEXT, INDEX, SELECTED, and DEPTH.  TEXT is the displayed text of the option
+(including parentheses, not including indentation); INDEX is the 0-based
+index of the option in the list (also used as its CGI parameter); SELECTED
+is either 'SELECTED' or '', depending on whether the node corresponding
+to the select option was in the SELECTED_NODES list; and DEPTH is the
+level of indentation for the option.
+
+=cut 
+
+sub GetQueryAndOptionList {
+    my $self           = shift;
+    my $selected_nodes = shift;
+
+    my $optionlist = [];
+
+    my $i = 0;
+
+    $self->TraversePrePost(
+        sub { # This is called before recursing to the node's children.
+            my $node = shift;
+
+            return if $node->isRoot or $node->getParent->isRoot;
+
+            my $clause = $node->getNodeValue();
+            my $str = ' ';
+            my $aggregator_context = $node->getParent()->getNodeValue();
+            $str = $aggregator_context . " " if $node->getIndex() > 0;
+
+            if ( ref($clause) ) { # ie, it's a leaf              
+                $str .=
+                  $clause->{Key} . " " . $clause->{Op} . " " . $clause->{Value};
+            }
+
+            unless ($node->getParent->getParent->isRoot) {
+        #        used to check !ref( $parent->getNodeValue() ) )
+                if ( $node->getIndex() == 0 ) {
+                    $str = '( ' . $str;
+                }
+            }
+
+            push @$optionlist, {
+                TEXT     => $str,
+                INDEX    => $i,
+                SELECTED => (grep { $_ == $node } @$selected_nodes) ? 'SELECTED' : '',
+                DEPTH    => $node->getDepth() - 1,
+            };
+
+            $i++;
+        }, sub {
+            # This is called after recursing to the node's children.
+            my $node = shift;
+
+            return if $node->isRoot or $node->getParent->isRoot or $node->getParent->getParent->isRoot;
+
+            # Only do this for the rightmost child.
+            return unless $node->getIndex == $node->getParent->getChildCount - 1;
+
+            $optionlist->[-1]{TEXT} .= ' )';
+        }
+    );
+
+    return (join ' ', map { $_->{TEXT} } @$optionlist), $optionlist;
+}
+
+=head2 PruneChildLessAggregators
+
+If tree manipulation has left it in a state where there are ANDs, ORs,
+or parenthesizations with no children, get rid of them.
+
+=cut
+
+sub PruneChildlessAggregators {
+    my $self = shift;
+
+    $self->TraversePrePost(
+        sub {
+        },
+        sub {
+            my $node = shift;
+
+            return if $node->isRoot or $node->getParent->isRoot;
+            
+            # We're only looking for aggregators (AND/OR)
+            return if ref $node->getNodeValue;
+            
+            return if $node->getChildCount != 0;
+            
+            # OK, this is a childless aggregator.  Remove self.
+            
+            $node->getParent->removeChild($node);
+            
+            # Deal with circular refs
+            $node->DESTROY;
+        }
+    );
+}
+
+=head2 GetDisplayedNodes
+
+This function returns a list of the nodes of the tree in depth-first
+order which correspond to options in the "clauses" multi-select box.
+In fact, it's all of them but the root and its child.
+
+=cut
+
+sub GetDisplayedNodes {
+    my $self = shift;
+    my @lines;
+
+    $self->traverse(sub {
+        my $node = shift;
+
+        push @lines, $node unless $node->isRoot or $node->getParent->isRoot;
+    });
+
+    return @lines;
+}
+
+
+eval "require RT::Interface::Web::QueryBuilder::Tree_Vendor";
+die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/Web/QueryBuilder/Tree_Vendor.pm});
+eval "require RT::Interface::Web::QueryBuilder::Tree_Local";
+die $@ if ($@ && $@ !~ qr{^Can't locate RT/Interface/Web/QueryBuilder/Tree_Local.pm});
+
+1;

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Transaction_Overlay.pm
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Transaction_Overlay.pm	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/RT/Transaction_Overlay.pm	Wed Jun  8 23:06:16 2005
@@ -662,7 +662,7 @@
         my $self = shift;
         my $Old = RT::User->new( $self->CurrentUser );
         $Old->Load( $self->OldValue );
-        return $self->loc("Stolen from [_1] ",  $Old->Name);
+        return $self->loc("Stolen from [_1]",  $Old->Name);
     },
     Give => sub {
         my $self = shift;

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/02basic_web.t
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/02basic_web.t	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/02basic_web.t	Wed Jun  8 23:06:16 2005
@@ -1,7 +1,7 @@
 #!/usr/bin/perl
 
 use strict;
-use Test::More 'no_plan';
+use Test::More tests => 17;
 use WWW::Mechanize;
 use HTTP::Request::Common;
 use HTTP::Cookies;

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/04send_email.t
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/04send_email.t	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/04send_email.t	Wed Jun  8 23:06:16 2005
@@ -1,7 +1,7 @@
 #!/usr/bin/perl -w
 
 use strict;
-use Test::More qw/no_plan/;
+use Test::More tests => 137;
 use RT;
 RT::LoadConfig();
 RT::Init;
@@ -50,6 +50,7 @@
 $tickets->OrderBy(FIELD => 'id', ORDER => 'DESC');
 $tickets->Limit(FIELD => 'id' ,OPERATOR => '>', VALUE => '0');
 my $tick= $tickets->First();
+isa_ok($tick, "RT::Ticket", "got a ticket object");
 ok ($tick->Id, "found ticket ".$tick->Id);
 
 ok ($tick->Transactions->First->Content =~ /The original message was received/, "It's the bounce");

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/09record_cf_api.t
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/09record_cf_api.t	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/09record_cf_api.t	Wed Jun  8 23:06:16 2005
@@ -2,7 +2,7 @@
 
 use strict;
 #use warnings FATAL => 'all';
-use Test::More qw/no_plan/;
+use Test::More tests => 130;
 
 use RT;
 RT::LoadConfig();

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/10merge.t
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/10merge.t	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/10merge.t	Wed Jun  8 23:06:16 2005
@@ -8,7 +8,7 @@
 # This test script validates that when merging two tickets, the comments from both tickets
 # are integrated into the new ticket
 
-use Test::More qw/no_plan/;
+use Test::More tests => 13;
 use RT;
 RT::LoadConfig;
 RT::Init;

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/11-template-insert.t
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/11-template-insert.t	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/11-template-insert.t	Wed Jun  8 23:06:16 2005
@@ -3,7 +3,7 @@
 use warnings;
 use strict;
 
-use Test::More qw/no_plan/;
+use Test::More tests => 7;
 
 use RT;
 RT::LoadConfig();

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/12-search.t
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/12-search.t	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/12-search.t	Wed Jun  8 23:06:16 2005
@@ -6,7 +6,7 @@
 use strict;
 use warnings;
 
-use Test::More qw/no_plan/;
+use Test::More tests => 35;
 use_ok('RT');
 RT::LoadConfig();
 RT::Init();

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/13-attribute-tests.t
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/13-attribute-tests.t	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/13-attribute-tests.t	Wed Jun  8 23:06:16 2005
@@ -1,5 +1,5 @@
 
-use Test::More qw/no_plan/;
+use Test::More tests => 24;
 use RT;
 RT::LoadConfig();
 RT::Init();

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/15cf_single_values_are_single.t
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/15cf_single_values_are_single.t	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/15cf_single_values_are_single.t	Wed Jun  8 23:06:16 2005
@@ -1,7 +1,7 @@
 #!/usr/bin/perl
 use warnings;
 use strict;
-use Test::More qw/no_plan/;
+use Test::More tests => 8;
 
 use RT;
 RT::LoadConfig();

Modified: rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/20savedsearch.t
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/20savedsearch.t	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/20savedsearch.t	Wed Jun  8 23:06:16 2005
@@ -1,5 +1,5 @@
 use RT;
-use Test::More qw/no_plan/;
+use Test::More tests => 26;
 use RT::User;
 use RT::Group;
 use RT::Ticket;

Added: rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/21query-builder.t
==============================================================================
--- (empty file)
+++ rt/branches/QUEBEC-EXPERIMENTAL/lib/t/regression/21query-builder.t	Wed Jun  8 23:06:16 2005
@@ -0,0 +1,204 @@
+#!/usr/bin/perl
+
+use strict;
+use Test::More tests => 31;
+use Test::WWW::Mechanize;
+use HTTP::Request::Common;
+use HTTP::Cookies;
+use LWP;
+use Encode;
+
+my $cookie_jar = HTTP::Cookies->new;
+my $agent = Test::WWW::Mechanize->new();
+
+# give the agent a place to stash the cookies
+
+$agent->cookie_jar($cookie_jar);
+
+use RT;
+RT::LoadConfig;
+
+# get the top page
+my $url = $RT::WebURL;
+$agent->get($url);
+
+is ($agent->{'status'}, 200, "Loaded a page");
+
+
+# {{{ test a login
+
+# follow the link marked "Login"
+
+ok($agent->{form}->find_input('user'));
+
+ok($agent->{form}->find_input('pass'));
+ok ($agent->{'content'} =~ /username:/i);
+$agent->field( 'user' => 'root' );
+$agent->field( 'pass' => 'password' );
+# the field isn't named, so we have to click link 0
+$agent->click(0);
+is($agent->{'status'}, 200, "Fetched the page ok");
+ok( $agent->{'content'} =~ /Logout/i, "Found a logout link");
+
+# }}}
+
+# {{{ Query Builder tests
+
+my $response = $agent->get($url."Search/Build.html");
+ok( $response->is_success, "Fetched " . $url."Search/Build.html" );
+
+# Adding items
+
+# set the first value
+ok($agent->form_name('BuildQuery'), "found the form once");
+$agent->field("ActorField", "Owner");
+$agent->field("ActorOp", "=");
+$agent->field("ValueOfActor", "Nobody");
+$agent->submit();
+
+# set the next value
+ok($agent->form_name('BuildQuery'), "found the form again");
+$agent->field("QueueOp", "!=");
+$agent->field("ValueOfQueue", "Regression");
+$agent->submit();
+
+ok($agent->form_name('BuildQuery'), "found the form a third time");
+
+sub getQueryFromForm {
+    # This pulls out the "hidden input" query from the page
+    my $q = $agent->current_form->find_input("Query")->value;
+    $q =~ s/^\s+//g;
+    $q =~ s/\s+$//g;
+    $q =~ s/\s+/ /g;
+    return $q;
+}
+
+is (getQueryFromForm, "Owner = 'Nobody' AND Queue != 'Regression'");
+
+# We're going to delete the owner
+
+$agent->select("clauses", ["0"] );
+
+$agent->click("DeleteClause");
+
+ok($agent->form_name('BuildQuery'), "found the form a fourth time");
+
+is (getQueryFromForm, "Queue != 'Regression'");
+
+$agent->field("AndOr", "OR");
+
+$agent->select("idOp", ">");
+
+$agent->field("ValueOfid" => "1234");
+
+$agent->click("AddClause");
+
+ok($agent->form_name('BuildQuery'), "found the form again");
+TODO: {
+  local $TODO = "query builder incorrectly quotes numbers";
+  is(getQueryFromForm, "Queue != 'Regression' OR id > 1234", "added something as OR, and number not quoted");
+}
+
+sub selectedClauses {
+    my @clauses = grep { defined } map { $_->value } $agent->current_form->find_input("clauses");
+    return [ @clauses ];
+}
+
+
+is_deeply(selectedClauses, ["1"], 'the id that we just entered is still selected');
+
+# Move the second one up a level
+$agent->click("Up"); 
+
+ok($agent->form_name('BuildQuery'), "found the form again");
+is(getQueryFromForm, "id > 1234 OR Queue != 'Regression'", "moved up one");
+
+is_deeply(selectedClauses, ["0"], 'the one we moved up is selected');
+
+$agent->click("Right");
+
+ok($agent->form_name('BuildQuery'), "found the form again");
+is(getQueryFromForm, "Queue != 'Regression' OR ( id > 1234 )", "moved over to the right (and down)");
+is_deeply(selectedClauses, ["2"], 'the one we moved right is selected');
+
+$agent->select("clauses", ["1"]);
+
+$agent->click("Up");
+
+ok($agent->form_name('BuildQuery'), "found the form again");
+TODO: {
+  local $TODO = "query builder incorrectly changes OR to AND";
+  is(getQueryFromForm, "( id > 1234 ) OR Queue != 'Regression'", "moved up");
+}
+
+$agent->select("clauses", ["0"]); # this is a null clause
+
+$agent->click("Up");
+
+ok($agent->form_name('BuildQuery'), "found the form again");
+
+$agent->content_like(qr/error: can\S+t move up/, "i shouldn't have been able to hit up");
+
+$agent->click("Left");
+
+ok($agent->form_name('BuildQuery'), "found the form again");
+
+$agent->content_like(qr/error: can\S+t move left/, "i shouldn't have been able to hit left");
+
+$agent->select("clauses", ["1"]);
+$agent->select("ValueOfStatus" => "stalled");
+
+$agent->submit;
+ok($agent->form_name('BuildQuery'), "found the form again");
+is_deeply(selectedClauses, ["2"], 'the one we added is selected');
+TODO: {
+  local $TODO = "query builder incorrectly changes OR to AND";
+  is(getQueryFromForm, "( id > 1234 AND Status = 'stalled' ) OR Queue != 'Regression'", "added new one");
+}
+
+
+
+# - new items go one level down
+# - add items at currently selected level
+# - if nothing is selected, add at end, one level down
+#
+# move left
+# - error if nothing selected
+# - same item should be selected after move
+# - can't move left if you're at the top level
+#
+# move right
+# - error if nothing selected
+# - same item should be selected after move
+# - can always move right (no max depth...should there be?)
+#
+# move up
+# - error if nothing selected
+# - same item should be selected after move
+# - can't move up if you're first in the list
+#
+# move down
+# - error if nothing selected
+# - same item should be selected after move
+# - can't move down if you're last in the list
+#
+# toggle
+# - error if nothing selected
+# - change all aggregators in the grouping
+# - don't change any others
+#
+# delete
+# - error if nothing selected
+# - delete currently selected item
+# - delete all children of a grouping
+# - if delete leaves a node with no children, delete that, too
+# - what should be selected?
+#
+# Clear
+# - clears entire query
+# - clears it from the session, too
+
+# }}}
+
+
+1;

Modified: rt/branches/QUEBEC-EXPERIMENTAL/sbin/rt-test-dependencies.in
==============================================================================
--- rt/branches/QUEBEC-EXPERIMENTAL/sbin/rt-test-dependencies.in	(original)
+++ rt/branches/QUEBEC-EXPERIMENTAL/sbin/rt-test-dependencies.in	Wed Jun  8 23:06:16 2005
@@ -52,7 +52,6 @@
 use strict;
 no warnings qw(numeric redefine);
 use Getopt::Long;
-use CPAN;
 my %args;
 my %deps;
 GetOptions(
@@ -80,8 +79,43 @@
 $args{'with-DEV'} =1; 
 $args{'with-CLI'} =1; 
 $args{'with-MAILGATE'} =1; 
-
-
+{
+  my $section;
+  my %always_show_sections = (
+    perl => 1,
+    users => 1,
+  );
+
+  sub section {
+    my $s = shift;
+    $section = $s;
+    print "$s:\n";
+  }
+
+  my $any_missing = 0;
+  sub found {
+    my $msg = shift;
+    my $test = shift;
+    my $extra = shift;
+  
+    $any_missing = 1 unless $test;
+    if ($args{'v'} or not $test or $always_show_sections{$section}) {
+      print "\t$msg...";
+      print $test ? "found" : "MISSING";
+      print "\n";
+    }
+    
+    print "\t\t$extra\n" if defined $extra;
+  }
+
+  sub conclude {
+    if ($any_missing) {
+      print "\nSOMETHING WAS MISSING!\n";
+    } else {
+      print "\nEverything was found.\n";
+    }
+  }
+}
 
 sub help {
 
@@ -243,7 +277,7 @@
 foreach my $type (keys %args) {
     next unless ($type =~ /^with-(.*?)$/);
     my $type = $1;
-    print "$type dependencies:\n";
+    section("$type dependencies");
     my @deps = (@{$deps{$type}});
     while (@deps) {
         my $module = shift @deps;
@@ -256,6 +290,8 @@
     }
 }
 
+conclude();
+
 sub test_dep {
     my $module = shift;
     my $version = shift;
@@ -264,26 +300,25 @@
     if ($@) {
         my $error = $@;
         $error =~ s/\n(.*)$//s;
-        print "\t$module $version";
-        print "...MISSING\n";
-        print "\t\t$error\n" if $error =~ /this is only/;
+        undef $error unless $error =~ /this is only/;
+        found("$module $version", 0, $error);
 
         return undef;
     } else {
-        print "\t$module $version...found\n" if $args{'v'};
+        found("$module $version", 1);
         return 1;
     }
 }
 
 sub resolve_dep {
     my $module = shift;
-    use CPAN;
-    CPAN::Shell->install($module);		
+    system( qq[@PERL@ -MCPAN -e'install("$module")'] );
 }
 
 sub download_mods {
     my %modules;
-
+    use CPAN;
+    
     foreach my $key (keys %deps) {
         my @deps = (@{$deps{$key}});
         while (@deps) {
@@ -322,38 +357,24 @@
 }
 
 sub check_perl_version {
-
-
-print "perl:\n";
-print "\t5.8.3";
-eval {require 5.008003};
-if ($@) {
-    print "...MISSING.\n";
-    eval {require 5.008000};
-    if ($@) {
-        print "\nRT is known to be non-functional on versions of perl older than 5.8.3.\nPlease upgrade to 5.8.3 or newer\n\n";
-        die;
-    } 
-
-    eval {require 5.008003};
-    if ($@) {
-        print "\nRT is known to be non-functional on versions of perl older than 5.8.3.\nPlease upgrade to 5.8.3 or newer\n\n";
-    }
-} else {
-    print "...found\n" if $args{'v'};
-}
+  section("perl");
+  eval {require 5.008003};
+  if ($@) {
+    found("5.8.3", 0, "RT is known to be non-functional on versions of perl older than 5.8.3. Please upgrade to 5.8.3 or newer.");
+    die;
+  } else {
+    found("5.8.3", 1);
+  }
 }
 
 sub check_users {
-
-print "users:\n";
-print "\trt group (@RTGROUP@)...",      (defined getgrnam("@RTGROUP@")    ? "found" : "MISSING"), "\n";
-print "\tbin owner (@BIN_OWNER@)...",   (defined getpwnam("@BIN_OWNER@")  ? "found" : "MISSING"), "\n";
-print "\tlibs owner (@LIBS_OWNER@)...", (defined getpwnam("@LIBS_OWNER@") ? "found" : "MISSING"), "\n";
-print "\tlibs group (@LIBS_GROUP@)...", (defined getgrnam("@LIBS_GROUP@") ? "found" : "MISSING"), "\n";
-print "\tweb owner (@WEB_USER@)...",    (defined getpwnam("@WEB_USER@")   ? "found" : "MISSING"), "\n";
-print "\tweb group (@WEB_GROUP@)...",   (defined getgrnam("@WEB_GROUP@")  ? "found" : "MISSING"), "\n";
-
+  section("users");
+  found("rt group (@RTGROUP@)",      defined getgrnam("@RTGROUP@"));
+  found("bin owner (@BIN_OWNER@)",   defined getpwnam("@BIN_OWNER@"));
+  found("libs owner (@LIBS_OWNER@)", defined getpwnam("@LIBS_OWNER@"));
+  found("libs group (@LIBS_GROUP@)", defined getgrnam("@LIBS_GROUP@"));
+  found("web owner (@WEB_USER@)",    defined getpwnam("@WEB_USER@"));
+  found("web group (@WEB_GROUP@)",   defined getgrnam("@WEB_GROUP@"));
 }
 
 


More information about the Rt-commit mailing list