[Rt-commit] rt branch, 4.4/signature-spacing, created. rt-4.4.0-114-g6733fad

Rachel Kelly rachel at bestpractical.com
Wed May 11 13:45:11 EDT 2016


The branch, 4.4/signature-spacing has been created
        at  6733fadcdd9b963056f51ec08079d1543abe98c0 (commit)

- Log -----------------------------------------------------------------
commit 344a35cf01d302d528851a6774c8006fd52f8108
Author: rachelkelly <rachel at bestpractical.com>
Date:   Thu May 5 07:05:25 2016 +0000

    Add regex to match against date-time-user Quote Header

diff --git a/t/web/signatures.t b/t/web/signatures.t
index becc1f9..ce1a118 100644
--- a/t/web/signatures.t
+++ b/t/web/signatures.t
@@ -4,11 +4,7 @@ use warnings;
 use RT::Test tests => undef;
 use HTML::Entities qw/decode_entities/;
 
-# Remove the timestamp from the quote header
-{
-    no warnings 'redefine';
-    *RT::Transaction::QuoteHeader = sub { "Someone wrote:" };
-}
+# Removed the: Remove the timestamp from the quote header
 
 my ($baseurl, $m) = RT::Test->started_ok;
 ok( $m->login, 'logged in' );
@@ -56,6 +52,8 @@ sub template_is {
     my $display = $value;
     $display =~ s/^$/./mg;
     $display =~ s/([ ]+)$/$1\$/mg;
+    $display =~ s/On .* wrote:/Someone wrote:/;
+
 
     is($display, $expected, "Content matches expected");
 

commit 77ed8ec613e1527e70fbd8e011e4898868641885
Author: rachelkelly <rachel at bestpractical.com>
Date:   Thu May 5 07:21:02 2016 +0000

    Fix failing FastCGI tests by changing how timestamps are removed from quote header
    
        From problematic commit 391c86194e3bcb07e682878cd163e0b9b7cd69cf
        which included faulty test re the timestamps added to headers.
    
        Added regex to match against timestamp so that the test would
        not pick it up - the timestamp will be different every time so
        it was necessary to elide past it.

diff --git a/t/web/signatures.t b/t/web/signatures.t
index ce1a118..7151efd 100644
--- a/t/web/signatures.t
+++ b/t/web/signatures.t
@@ -4,8 +4,6 @@ use warnings;
 use RT::Test tests => undef;
 use HTML::Entities qw/decode_entities/;
 
-# Removed the: Remove the timestamp from the quote header
-
 my ($baseurl, $m) = RT::Test->started_ok;
 ok( $m->login, 'logged in' );
 
@@ -49,11 +47,11 @@ sub template_is {
 
     # For ease of interpretation, replace blank lines with dots, and
     # put a $ after trailing whitespace.
+    # Remove the timestamp from the quote header
     my $display = $value;
     $display =~ s/^$/./mg;
     $display =~ s/([ ]+)$/$1\$/mg;
-    $display =~ s/On .* wrote:/Someone wrote:/;
-
+    $display =~ s/On \w\w\w \w\w\w \d\d \d\d:\d\d:\d\d \d\d\d\d, \w+:/Someone wrote:/
 
     is($display, $expected, "Content matches expected");
 

commit 6733fadcdd9b963056f51ec08079d1543abe98c0
Author: rachelkelly <rachel at bestpractical.com>
Date:   Fri May 6 02:27:44 2016 +0000

    Fix failing FastCGI tests by changing how timestamps are removed from quote header
    
        This fix fixes a test failure which was occurring because
        the test was not written to account for the auto-filled
        time, date, and user on any given RT ticket.  Substitution
        regex was written to account for this time, date & user in
        a general sense and, for the FastCGI test (which generates
        a ticket to test against), replace the time, date, and user
        with the phrase "Someone wrote:".
    
        Further, this commit is a result of fixing some serious
        rebasing problems.  The commit that is being fixed from the
        problematic test is Alex's older commit:
        9df4d3387e22754f160a5aba91f2e25381309b45

diff --git a/lib/RT/Action/CreateTickets.pm b/lib/RT/Action/CreateTickets.pm
index 75b38b1..dd32da7 100644
--- a/lib/RT/Action/CreateTickets.pm
+++ b/lib/RT/Action/CreateTickets.pm
@@ -1140,7 +1140,7 @@ sub UpdateCustomFields {
 
         foreach my $value (@values) {
             next if $ticket->CustomFieldValueIsEmpty(
-                Field => $CustomFieldObj,
+                Field => $cf,
                 Value => $value,
             );
             my ( $val, $msg ) = $ticket->AddCustomFieldValue(
diff --git a/lib/RT/Article.pm b/lib/RT/Article.pm
index 6eb9640..e8ea75c 100644
--- a/lib/RT/Article.pm
+++ b/lib/RT/Article.pm
@@ -147,8 +147,7 @@ sub Create {
                     : (Value => $value)
                 ),
                 Field             => $cf,
-                RecordTransaction => 0,
-                ForCreation       => 1,
+                RecordTransaction => 0
             );
 
             unless ($cfid) {
diff --git a/lib/RT/Asset.pm b/lib/RT/Asset.pm
index b2e75bb..c9efb08 100644
--- a/lib/RT/Asset.pm
+++ b/lib/RT/Asset.pm
@@ -293,8 +293,7 @@ sub Create {
                     ? %$value
                     : (Value => $value)),
                 Field             => $cf,
-                RecordTransaction => 0,
-                ForCreation       => 1,
+                RecordTransaction => 0
             );
             unless ($cfid) {
                 RT->DatabaseHandle->Rollback();
diff --git a/lib/RT/Catalog.pm b/lib/RT/Catalog.pm
index c6b457c..1ed8585 100644
--- a/lib/RT/Catalog.pm
+++ b/lib/RT/Catalog.pm
@@ -83,9 +83,8 @@ __PACKAGE__->AddRight( General => ShowAsset    => 'See assets' ); #loc
 __PACKAGE__->AddRight( Staff   => CreateAsset  => 'Create assets' ); #loc
 __PACKAGE__->AddRight( Staff   => ModifyAsset  => 'Modify assets' ); #loc
 
-__PACKAGE__->AddRight( General => SeeCustomField        => 'View custom field values' ); # loc
-__PACKAGE__->AddRight( Staff   => ModifyCustomField     => 'Modify custom field values' ); # loc
-__PACKAGE__->AddRight( Staff   => SetInitialCustomField => 'Add custom field values only at object creation time'); # loc
+__PACKAGE__->AddRight( General => SeeCustomField      => 'View custom field values' ); # loc
+__PACKAGE__->AddRight( Staff   => ModifyCustomField   => 'Modify custom field values' ); # loc
 
 RT::ACE->RegisterCacheHandler(sub {
     my %args = (
diff --git a/lib/RT/Class.pm b/lib/RT/Class.pm
index 71315ab..99faf19 100644
--- a/lib/RT/Class.pm
+++ b/lib/RT/Class.pm
@@ -84,20 +84,19 @@ sub Load {
     }
 }
 
-__PACKAGE__->AddRight( Staff   => SeeClass              => 'See that this class exists'); # loc
-__PACKAGE__->AddRight( Staff   => CreateArticle         => 'Create articles in this class'); # loc
-__PACKAGE__->AddRight( General => ShowArticle           => 'See articles in this class'); # loc
-__PACKAGE__->AddRight( Staff   => ShowArticleHistory    => 'See changes to articles in this class'); # loc
-__PACKAGE__->AddRight( General => SeeCustomField        => 'View custom field values' ); # loc
-__PACKAGE__->AddRight( Staff   => ModifyArticle         => 'Modify articles in this class'); # loc
-__PACKAGE__->AddRight( Staff   => ModifyArticleTopics   => 'Modify topics for articles in this class'); # loc
-__PACKAGE__->AddRight( Staff   => ModifyCustomField     => 'Modify custom field values' ); # loc
-__PACKAGE__->AddRight( Staff   => SetInitialCustomField => 'Add custom field values only at object creation time'); # loc
-__PACKAGE__->AddRight( Admin   => AdminClass            => 'Modify metadata and custom fields for this class'); # loc
-__PACKAGE__->AddRight( Admin   => AdminTopics           => 'Modify topic hierarchy associated with this class'); # loc
-__PACKAGE__->AddRight( Admin   => ShowACL               => 'Display Access Control List'); # loc
-__PACKAGE__->AddRight( Admin   => ModifyACL             => 'Create, modify and delete Access Control List entries'); # loc
-__PACKAGE__->AddRight( Staff   => DisableArticle        => 'Disable articles in this class'); # loc
+__PACKAGE__->AddRight( Staff   => SeeClass            => 'See that this class exists'); # loc
+__PACKAGE__->AddRight( Staff   => CreateArticle       => 'Create articles in this class'); # loc
+__PACKAGE__->AddRight( General => ShowArticle         => 'See articles in this class'); # loc
+__PACKAGE__->AddRight( Staff   => ShowArticleHistory  => 'See changes to articles in this class'); # loc
+__PACKAGE__->AddRight( General => SeeCustomField      => 'View custom field values' ); # loc
+__PACKAGE__->AddRight( Staff   => ModifyArticle       => 'Modify articles in this class'); # loc
+__PACKAGE__->AddRight( Staff   => ModifyArticleTopics => 'Modify topics for articles in this class'); # loc
+__PACKAGE__->AddRight( Staff   => ModifyCustomField   => 'Modify custom field values' ); # loc
+__PACKAGE__->AddRight( Admin   => AdminClass          => 'Modify metadata and custom fields for this class'); # loc
+__PACKAGE__->AddRight( Admin   => AdminTopics         => 'Modify topic hierarchy associated with this class'); # loc
+__PACKAGE__->AddRight( Admin   => ShowACL             => 'Display Access Control List'); # loc
+__PACKAGE__->AddRight( Admin   => ModifyACL           => 'Create, modify and delete Access Control List entries'); # loc
+__PACKAGE__->AddRight( Staff   => DisableArticle      => 'Disable articles in this class'); # loc
 
 # {{{ Create
 
diff --git a/lib/RT/CustomField.pm b/lib/RT/CustomField.pm
index e317810..a6fb1d7 100644
--- a/lib/RT/CustomField.pm
+++ b/lib/RT/CustomField.pm
@@ -214,7 +214,6 @@ __PACKAGE__->AddRight( General => SeeCustomField         => 'View custom fields'
 __PACKAGE__->AddRight( Admin   => AdminCustomField       => 'Create, modify and delete custom fields'); # loc
 __PACKAGE__->AddRight( Admin   => AdminCustomFieldValues => 'Create, modify and delete custom fields values'); # loc
 __PACKAGE__->AddRight( Staff   => ModifyCustomField      => 'Add, modify and delete custom field values for objects'); # loc
-__PACKAGE__->AddRight( Staff   => SetInitialCustomField  => 'Add custom field values only at object creation time'); # loc
 
 =head1 NAME
 
@@ -611,7 +610,7 @@ sub Values {
     my $cf_values = $class->new( $self->CurrentUser );
     $cf_values->SetCustomFieldObject( $self );
     # if the user has no rights, return an empty object
-    if ( $self->id && $self->CurrentUserCanSee ) {
+    if ( $self->id && $self->CurrentUserHasRight( 'SeeCustomField') ) {
         $cf_values->LimitToCustomField( $self->Id );
     } else {
         $cf_values->Limit( FIELD => 'id', VALUE => 0, SUBCLAUSE => 'acl' );
@@ -1050,7 +1049,7 @@ sub _Value {
     return undef unless $self->id;
 
     # we need to do the rights check
-    unless ( $self->CurrentUserCanSee ) {
+    unless ( $self->CurrentUserHasRight('SeeCustomField') ) {
         $RT::Logger->debug(
             "Permission denied. User #". $self->CurrentUser->id
             ." has no SeeCustomField right on CF #". $self->id
@@ -1640,15 +1639,11 @@ sub AddValueForObject {
         Content      => undef,
         LargeContent => undef,
         ContentType  => undef,
-        ForCreation  => 0,
         @_
     );
     my $obj = $args{'Object'} or return ( 0, $self->loc('Invalid object') );
 
-    unless (
-        $self->CurrentUserHasRight('ModifyCustomField') ||
-        ($args{ForCreation} && $self->CurrentUserHasRight('SetInitialCustomField'))
-    ) {
+    unless ( $self->CurrentUserHasRight('ModifyCustomField') ) {
         return ( 0, $self->loc('Permission Denied') );
     }
 
@@ -1870,7 +1865,7 @@ sub ValuesForObject {
     my $object = shift;
 
     my $values = RT::ObjectCustomFieldValues->new($self->CurrentUser);
-    unless ($self->id and $self->CurrentUserCanSee) {
+    unless ($self->id and $self->CurrentUserHasRight('SeeCustomField')) {
         # Return an empty object if they have no rights to see
         $values->Limit( FIELD => "id", VALUE => 0, SUBCLAUSE => "ACL" );
         return ($values);
@@ -1882,26 +1877,6 @@ sub ValuesForObject {
     return ($values);
 }
 
-=head2 CurrentUserCanSee
-
-If the user has SeeCustomField they can see this custom field and its details.
-
-Otherwise, if the user has SetInitialCustomField and this is being used in a
-"create" context, then they can see this custom field and its details. This
-allows you to set up custom fields that are only visible on create pages and
-are then inaccessible.
-
-=cut
-
-sub CurrentUserCanSee {
-    my $self = shift;
-    return 1 if $self->CurrentUserHasRight('SeeCustomField');
-
-    return 1 if $self->{include_set_initial}
-             && $self->CurrentUserHasRight('SetInitialCustomField');
-
-    return 0;
-}
 
 =head2 RegisterLookupType LOOKUPTYPE FRIENDLYNAME
 
@@ -1991,7 +1966,7 @@ sub _URLTemplate {
         }
         return ( 1, $self->loc('Updated') );
     } else {
-        unless ( $self->id && $self->CurrentUserCanSee ) {
+        unless ( $self->id && $self->CurrentUserHasRight('SeeCustomField') ) {
             return (undef);
         }
 
@@ -2013,7 +1988,7 @@ sub SetBasedOn {
     $cf->Load( ref $value ? $value->id : $value );
 
     return (0, "Permission Denied")
-        unless $cf->id && $cf->CurrentUserCanSee;
+        unless $cf->id && $cf->CurrentUserHasRight('SeeCustomField');
 
     # XXX: Remove this restriction once we support lists and cascaded selects
     if ( $self->RenderType =~ /List/ ) {
diff --git a/lib/RT/CustomFields.pm b/lib/RT/CustomFields.pm
index 7ef55da..d421ead 100644
--- a/lib/RT/CustomFields.pm
+++ b/lib/RT/CustomFields.pm
@@ -403,10 +403,7 @@ sub AddRecord {
     my ($record) = @_;
 
     $record->SetContextObject( $self->ContextObject );
-    $record->{include_set_initial} = $self->{include_set_initial};
-
-    return unless $record->CurrentUserCanSee;
-
+    return unless $record->CurrentUserHasRight('SeeCustomField');
     return $self->SUPER::AddRecord( $record );
 }
 
diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index 17a73e6..f01337c 100644
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -3211,7 +3211,7 @@ sub _ProcessObjectCustomFieldUpdates {
         if ( $arg eq 'AddValue' || $arg eq 'Value' ) {
             foreach my $value (@values) {
                 next if $args{'Object'}->CustomFieldValueIsEmpty(
-                    Field => $cf,
+                    Field => $cf->id,
                     Value => $value,
                 );
                 my ( $val, $msg ) = $args{'Object'}->AddCustomFieldValue(
@@ -3306,7 +3306,6 @@ sub ProcessObjectCustomFieldUpdatesForCreate {
         # we're only interested in new objects, so only look at $id == 0
         for my $cfid (keys %{ $custom_fields{$class}{0} || {} }) {
             my $cf = RT::CustomField->new( $session{'CurrentUser'} );
-            $cf->{include_set_initial} = 1;
             if ($context) {
                 my $system_cf = RT::CustomField->new( RT->SystemUser );
                 $system_cf->LoadById($cfid);
diff --git a/lib/RT/ObjectCustomFieldValue.pm b/lib/RT/ObjectCustomFieldValue.pm
index 101f9e9..7235ed1 100644
--- a/lib/RT/ObjectCustomFieldValue.pm
+++ b/lib/RT/ObjectCustomFieldValue.pm
@@ -221,14 +221,11 @@ my $re_ip_serialized = qr/$re_ip_sunit(?:\.$re_ip_sunit){3}/;
 sub Content {
     my $self = shift;
 
-    my $cf = $self->CustomFieldObj;
-    $cf->{include_set_initial} = $self->{include_set_initial};
-
-    return undef unless $cf->CurrentUserCanSee;
+    return undef unless $self->CustomFieldObj->CurrentUserHasRight('SeeCustomField');
 
     my $content = $self->_Value('Content');
-    if (   $cf->Type eq 'IPAddress'
-        || $cf->Type eq 'IPAddressRange' )
+    if (   $self->CustomFieldObj->Type eq 'IPAddress'
+        || $self->CustomFieldObj->Type eq 'IPAddressRange' )
     {
 
         require Net::IP;
@@ -239,7 +236,7 @@ sub Content {
             $content = Net::IP::ip_compress_address($1, 6);
         }
 
-        return $content if $cf->Type eq 'IPAddress';
+        return $content if $self->CustomFieldObj->Type eq 'IPAddress';
 
         my $large_content = $self->__Value('LargeContent');
         if ( $large_content =~ /^\s*($re_ip_serialized)\s*$/o ) {
diff --git a/lib/RT/Queue.pm b/lib/RT/Queue.pm
index b3940b3..7565b1d 100644
--- a/lib/RT/Queue.pm
+++ b/lib/RT/Queue.pm
@@ -100,17 +100,16 @@ use RT::CustomRoles;
 use RT::ACL;
 use RT::Interface::Email;
 
-__PACKAGE__->AddRight( General => SeeQueue              => 'View queue' ); # loc
-__PACKAGE__->AddRight( Admin   => AdminQueue            => 'Create, modify and delete queue' ); # loc
-__PACKAGE__->AddRight( Admin   => ShowACL               => 'Display Access Control List' ); # loc
-__PACKAGE__->AddRight( Admin   => ModifyACL             => 'Create, modify and delete Access Control List entries' ); # loc
-__PACKAGE__->AddRight( Admin   => ModifyQueueWatchers   => 'Modify queue watchers' ); # loc
-__PACKAGE__->AddRight( General => SeeCustomField        => 'View custom field values' ); # loc
-__PACKAGE__->AddRight( Staff   => ModifyCustomField     => 'Modify custom field values' ); # loc
-__PACKAGE__->AddRight( Staff   => SetInitialCustomField => 'Add custom field values only at object creation time'); # loc
-__PACKAGE__->AddRight( Admin   => AssignCustomFields    => 'Assign and remove queue custom fields' ); # loc
-__PACKAGE__->AddRight( Admin   => ModifyTemplate        => 'Modify Scrip templates' ); # loc
-__PACKAGE__->AddRight( Admin   => ShowTemplate          => 'View Scrip templates' ); # loc
+__PACKAGE__->AddRight( General => SeeQueue            => 'View queue' ); # loc
+__PACKAGE__->AddRight( Admin   => AdminQueue          => 'Create, modify and delete queue' ); # loc
+__PACKAGE__->AddRight( Admin   => ShowACL             => 'Display Access Control List' ); # loc
+__PACKAGE__->AddRight( Admin   => ModifyACL           => 'Create, modify and delete Access Control List entries' ); # loc
+__PACKAGE__->AddRight( Admin   => ModifyQueueWatchers => 'Modify queue watchers' ); # loc
+__PACKAGE__->AddRight( General => SeeCustomField      => 'View custom field values' ); # loc
+__PACKAGE__->AddRight( Staff   => ModifyCustomField   => 'Modify custom field values' ); # loc
+__PACKAGE__->AddRight( Admin   => AssignCustomFields  => 'Assign and remove queue custom fields' ); # loc
+__PACKAGE__->AddRight( Admin   => ModifyTemplate      => 'Modify Scrip templates' ); # loc
+__PACKAGE__->AddRight( Admin   => ShowTemplate        => 'View Scrip templates' ); # loc
 
 __PACKAGE__->AddRight( Admin   => ModifyScrips        => 'Modify Scrips' ); # loc
 __PACKAGE__->AddRight( Admin   => ShowScrips          => 'View Scrips' ); # loc
diff --git a/lib/RT/Record.pm b/lib/RT/Record.pm
index 6d24385..2d96103 100644
--- a/lib/RT/Record.pm
+++ b/lib/RT/Record.pm
@@ -1937,13 +1937,10 @@ sub _AddCustomFieldValue {
         LargeContent      => undef,
         ContentType       => undef,
         RecordTransaction => 1,
-        ForCreation       => 0,
         @_
     );
 
     my $cf = $self->LoadCustomFieldByIdentifier($args{'Field'});
-    $cf->{include_set_initial} = 1 if $args{'ForCreation'};
-
     unless ( $cf->Id ) {
         return ( 0, $self->loc( "Custom field [_1] not found", $args{'Field'} ) );
     }
@@ -2018,7 +2015,6 @@ sub _AddCustomFieldValue {
             Content      => $args{'Value'},
             LargeContent => $args{'LargeContent'},
             ContentType  => $args{'ContentType'},
-            ForCreation  => $args{'ForCreation'},
         );
 
         unless ( $new_value_id ) {
@@ -2026,7 +2022,6 @@ sub _AddCustomFieldValue {
         }
 
         my $new_value = RT::ObjectCustomFieldValue->new( $self->CurrentUser );
-        $new_value->{include_set_initial} = 1 if $args{'ForCreation'};
         $new_value->Load( $new_value_id );
 
         # now that adding the new value was successful, delete the old one
@@ -2127,7 +2122,7 @@ sub AddCustomFieldDefaultValues {
         my $values = $cf->DefaultValues( Object => $on || RT->System );
         foreach my $value ( UNIVERSAL::isa( $values => 'ARRAY' ) ? @$values : $values ) {
             next if $self->CustomFieldValueIsEmpty(
-                Field => $cf,
+                Field => $cf->id,
                 Value => $value,
             );
 
@@ -2164,10 +2159,7 @@ sub CustomFieldValueIsEmpty {
     my $value = $args{Value};
     return 1 unless defined $value  && length $value;
 
-    my $cf = ref($args{'Field'})
-           ? $args{'Field'}
-           : $self->LoadCustomFieldByIdentifier( $args{'Field'} );
-
+    my $cf = $self->LoadCustomFieldByIdentifier( $args{'Field'} );
     if ($cf) {
         if ( $cf->Type =~ /^Date(?:Time)?$/ ) {
             my $DateObj = RT::Date->new( $self->CurrentUser );
diff --git a/lib/RT/Ticket.pm b/lib/RT/Ticket.pm
index 3fa0557..bd17619 100644
--- a/lib/RT/Ticket.pm
+++ b/lib/RT/Ticket.pm
@@ -484,14 +484,13 @@ sub Create {
         next unless $arg =~ /^CustomField-(\d+)$/i;
         my $cfid = $1;
         my $cf = $self->LoadCustomFieldByIdentifier($cfid);
-        $cf->{include_set_initial} = 1;
         next unless $cf->ObjectTypeFromLookupType($cf->__Value('LookupType'))->isa(ref $self);
 
         foreach my $value (
             UNIVERSAL::isa( $args{$arg} => 'ARRAY' ) ? @{ $args{$arg} } : ( $args{$arg} ) )
         {
             next if $self->CustomFieldValueIsEmpty(
-                Field => $cf,
+                Field => $cfid,
                 Value => $value,
             );
 
@@ -503,7 +502,6 @@ sub Create {
                 ),
                 Field             => $cfid,
                 RecordTransaction => 0,
-                ForCreation       => 1,
             );
             push @non_fatal_errors, $msg unless $status;
         }
diff --git a/lib/RT/Transaction.pm b/lib/RT/Transaction.pm
index 9afdedf..774fbe3 100644
--- a/lib/RT/Transaction.pm
+++ b/lib/RT/Transaction.pm
@@ -1423,7 +1423,7 @@ sub CurrentUserCanSee {
         my $cf = RT::CustomField->new( $self->CurrentUser );
         $cf->SetContextObject( $self->Object );
         $cf->Load( $cf_id );
-        return 0 unless $cf->CurrentUserCanSee;
+        return 0 unless $cf->CurrentUserHasRight('SeeCustomField');
     }
 
     # Transactions that might have changed the ->Object's visibility to
@@ -1539,7 +1539,7 @@ sub UpdateCustomFields {
           my $value ( UNIVERSAL::isa( $values, 'ARRAY' ) ? @$values : $values )
         {
             next if $self->CustomFieldValueIsEmpty(
-                Field => $cf,
+                Field => $cfid,
                 Value => $value,
             );
             $self->_AddCustomFieldValue(
diff --git a/share/html/Articles/Article/Edit.html b/share/html/Articles/Article/Edit.html
index 36d21e9..f2905e6 100644
--- a/share/html/Articles/Article/Edit.html
+++ b/share/html/Articles/Article/Edit.html
@@ -67,8 +67,7 @@
                               CFContent => \%CFContent,
                               ClassObj => $ClassObj,
                               %ARGS,
-                              id => $id,
-                              ForCreation => ($id eq 'new'),
+                              id =>$id,
                               &>
 </&>
 
diff --git a/share/html/Asset/Create.html b/share/html/Asset/Create.html
index d059ec9..1d258ce 100644
--- a/share/html/Asset/Create.html
+++ b/share/html/Asset/Create.html
@@ -94,9 +94,7 @@
         Object => $asset,
         TitleBoxARGS => { title_class => "inverse" },
         KeepValue => 1,
-        CustomFieldGenerator => sub { $catalog->AssetCustomFields },
-        ForCreation => 1,
-  &>
+        CustomFieldGenerator => sub { $catalog->AssetCustomFields } &>
 </div>
 
   <& /Elements/Submit, Label => loc('Create asset') &>
diff --git a/share/html/Elements/EditCustomFields b/share/html/Elements/EditCustomFields
index fbfb5ed..79174de 100644
--- a/share/html/Elements/EditCustomFields
+++ b/share/html/Elements/EditCustomFields
@@ -47,18 +47,11 @@
 %# END BPS TAGGED BLOCK }}}
 % $m->callback( CallbackName => 'BeforeCustomFields', Object => $Object,
 %               Grouping => $Grouping, ARGSRef => \%ARGS, CustomFields => $CustomFields);
-
-%# only show the wrapper if there are editable custom fields, so we can
-%# suppress the empty titlebox. we do this in such a way that we still call the
-%# BeforeCustomFields and AfterCustomFields callbacks (rather than returning
-%# from the INIT block) to maintain compatibility with old behavior
-
-% if (@CustomFields) {
-
 % if ( $WRAP ) {
 <<% $WRAP %> class="edit-custom-fields">
 % }
-% for my $CustomField (@CustomFields) {
+% while ( my $CustomField = $CustomFields->Next ) {
+% next unless $CustomField->CurrentUserHasRight('ModifyCustomField');
 % my $Type = $CustomField->Type || 'Unknown';
 
   <<% $FIELD %> class="edit-custom-field cftype-<% $Type %>">
@@ -92,27 +85,18 @@
 % if ( $WRAP ) {
 </<% $WRAP %>>
 % }
-
-% }
-
 % $m->callback( CallbackName => 'AfterCustomFields', Object => $Object,
 %               Grouping => $Grouping, ARGSRef => \%ARGS );
 <%INIT>
 $CustomFields ||= $Object->CustomFields;
-$CustomFields->{include_set_initial} = 1 if $ForCreation;
 
 $CustomFields->LimitToGrouping( $Object => $Grouping ) if defined $Grouping;
 
 $m->callback( %ARGS, CallbackName => 'MassageCustomFields', CustomFields => $CustomFields );
 
+# don't print anything if there is no custom fields
+return unless $CustomFields->First;
 $CustomFields->GotoFirstItem;
-my @CustomFields;
-while ( my $CustomField = $CustomFields->Next ) {
-    next unless $CustomField->CurrentUserHasRight('ModifyCustomField')
-             || ($ForCreation && $CustomField->CurrentUserHasRight('SetInitialCustomField'));
-
-    push @CustomFields, $CustomField;
-}
 
 $AsTable ||= $InTable;
 my $FIELD = $AsTable ? 'tr' : 'div';
@@ -132,5 +116,4 @@ $Grouping     => undef
 $AsTable => 1
 $InTable => 0
 $ShowHints => 1
-$ForCreation => 0
 </%ARGS>
diff --git a/share/html/Helpers/TicketTimer b/share/html/Helpers/TicketTimer
index 2a8b0d6..c0f58c2 100644
--- a/share/html/Helpers/TicketTimer
+++ b/share/html/Helpers/TicketTimer
@@ -52,64 +52,46 @@ $id
 my $Ticket = RT::Ticket->new($session{'CurrentUser'});
 $Ticket->Load( $id );
 
-my $UnpauseImg = RT->Config->Get('WebPath') . '/static/images/unpause.png';
-my $PauseImg   = RT->Config->Get('WebPath') . '/static/images/pause.png';
+my $unpause_img = RT->Config->Get('WebPath') . '/static/images/unpause.png';
+my $pause_img   = RT->Config->Get('WebPath') . '/static/images/pause.png';
 
-my $Now = RT::Date->new($session{'CurrentUser'});
-$Now->SetToNow;
+my $now = RT::Date->new($session{'CurrentUser'});
+$now->SetToNow;
 
-my $SubmitURL = RT->Config->Get('WebPath') . '/Helpers/AddTimeWorked';
+my $submit_url = RT->Config->Get('WebPath') . '/Helpers/AddTimeWorked';
 </%INIT>
 <& /Elements/Header, Title => loc('Timer for #[_1]: [_2]', $Ticket->Id, $Ticket->Subject), RichText => 0, ShowBar => 0, ShowTitle => 0 &>
 
 <script type="text/javascript">
 jQuery( function() {
     var Interval;
+    var Seconds = 0;
 
-    // LastUnpause tracks when the current timer started. Then we render
-    // (current time - LastUnpause). This is more reliable than a timer
-    // that ticks up every second. For example, if JavaScript is temporarily
-    // paused (such as being on a background browser tab on a mobile device),
-    // the seconds ticker doesn't run. When the timer is paused, LastUnpaused
-    // will be a false value.
-    var LastUnpause = (new Date).getTime() / 1000;
-
-    // How many seconds has passed since the current timer started?
-    var CurrentSeconds = function () {
-        if (!LastUnpause) return 0;
-        return Math.floor(((new Date).getTime() / 1000) - LastUnpause);
-    };
-
-    // CommittedSeconds tracks how long we've "committed" time, which is
-    // different from when the timer was initially launched, due to unpausing.
-    // Every time we pause, we add (current time - LastUnpause) to
-    // CommittedSeconds.
-    var CommittedSeconds = 0;
-
-    var Readout = jQuery('.readout');
-    var PlayPause = jQuery('.playpause');
-    var PlayPauseImg = PlayPause.find('img');
+    var readout = jQuery('.readout');
+    var playpause = jQuery('.playpause');
+    var playpause_img = playpause.find('img');
 
-    var PauseAlt = PlayPauseImg.attr('alt');
-    var UnpauseAlt = PlayPauseImg.data('toggle-alt');
+    var pause_alt = playpause_img.attr('alt');
+    var unpause_alt = playpause_img.data('toggle-alt');
 
-    var ToHHMMSS = function (Total) {
-        var Hours   = Math.floor(Total / 3600);
-        var Minutes = Math.floor((Total - (Hours * 3600)) / 60);
-        var Seconds = Total - (Hours * 3600) - (Minutes * 60);
+    var toHHMMSS = function (total) {
+        var hours   = Math.floor(total / 3600);
+        var minutes = Math.floor((total - (hours * 3600)) / 60);
+        var seconds = total - (hours * 3600) - (minutes * 60);
 
-        if (Minutes < 10) { Minutes = "0" + Minutes; }
-        if (Seconds < 10) { Seconds = "0" + Seconds; }
+        if (minutes < 10) { minutes = "0" + minutes; }
+        if (seconds < 10) { seconds = "0" + seconds; }
 
-        return Hours + ':' + Minutes + ':' + Seconds;
+        return hours + ':' + minutes + ':' + seconds;
     };
 
-    var RenderReadout = function (seconds) {
-        Readout.text(ToHHMMSS(seconds));
+    var renderReadout = function (seconds) {
+        readout.text(toHHMMSS(seconds));
     };
 
-    var Tick = function () {
-        RenderReadout(CommittedSeconds + CurrentSeconds());
+    var tick = function () {
+        Seconds++;
+        renderReadout(Seconds);
     };
 
     jQuery('.playpause').click(function () {
@@ -117,19 +99,16 @@ jQuery( function() {
             // pause
             clearInterval(Interval);
             Interval = false;
-            CommittedSeconds += CurrentSeconds();
-            LastUnpause = false;
-            PlayPauseImg.attr('src', <% $UnpauseImg |n,j %>);
-            PlayPauseImg.attr('alt', UnpauseAlt);
-            PlayPauseImg.attr('title', UnpauseAlt);
+            playpause_img.attr('src', <% $unpause_img |n,j %>);
+            playpause_img.attr('alt', unpause_alt);
+            playpause_img.attr('title', unpause_alt);
         }
         else {
             // unpause
-            Interval = setInterval(Tick, 1000);
-            LastUnpause = new Date().getTime() / 1000;
-            PlayPauseImg.attr('src', <% $PauseImg |n,j %>);
-            PlayPauseImg.attr('alt', PauseAlt);
-            PlayPauseImg.attr('title', PauseAlt);
+            Interval = setInterval(tick, 1000);
+            playpause_img.attr('src', <% $pause_img |n,j %>);
+            playpause_img.attr('alt', pause_alt);
+            playpause_img.attr('title', pause_alt);
         }
         return false;
     });
@@ -137,41 +116,40 @@ jQuery( function() {
     jQuery('.submit-time').click(function () {
         clearInterval(Interval);
         jQuery('.control-line a').hide();
-        CommittedSeconds += CurrentSeconds();
 
-        var Payload = {
+        var payload = {
             id: <% $Ticket->id %>,
-            seconds: CommittedSeconds
+            seconds: Seconds
         };
 
-        Readout.text('<% loc("Submitting") %>');
+        readout.text('<% loc("Submitting") %>');
 
-        var RenderSubmitError = function (Reason) {
-            RenderReadout(CommittedSeconds);
+        var renderSubmitError = function (reason) {
+            renderReadout(Seconds);
             jQuery('.ticket-timer').addClass('error');
 
             // give the browser a chance to redraw the readout
             setTimeout(function () {
-                alert('<% loc("Unable to submit time. Please add it to the ticket manually. Reason:") %>' + ' ' + Reason);
+                alert('<% loc("Unable to submit time. Please add it to the ticket manually. Reason:") %>' + ' ' + reason);
             }, 100);
         };
 
         jQuery.ajax({
-            url: <% $SubmitURL |n,j %>,
-            data: Payload,
+            url: <% $submit_url |n,j %>,
+            data: payload,
             timeout: 30000, /* 30 seconds */
-            success: function (Response) {
-                if (Response.ok) {
-                    Readout.addClass('response');
-                    Readout.text(Response.msg);
+            success: function (response) {
+                if (response.ok) {
+                    readout.addClass('response');
+                    readout.text(response.msg);
                     jQuery('.control-line .close-popup').show().removeClass('hidden');
                 }
                 else {
-                    RenderSubmitError(Response.msg);
+                    renderSubmitError(response.msg);
                 }
             },
             error: function (xhr, reason) {
-                RenderSubmitError(reason);
+                renderSubmitError(reason);
             }
         });
 
@@ -183,8 +161,8 @@ jQuery( function() {
         return false;
     });
 
-    Tick();
-    Interval = setInterval(Tick, 500);
+    renderReadout(Seconds);
+    Interval = setInterval(tick, 1000);
 });
 </script>
 
@@ -200,13 +178,13 @@ jQuery( function() {
         <div class="readout"></div>
 
         <div class="control-line">
-            <a href="#" class="playpause"><img src="<% $PauseImg %>" alt="<% loc('Pause Timer') %>" data-toggle-alt="<% loc('Resume Timer') %>" title="<% loc('Pause Timer') %>" /></a>
+            <a href="#" class="playpause"><img src="<% $pause_img %>" alt="<% loc('Pause Timer') %>" data-toggle-alt="<% loc('Resume Timer') %>" title="<% loc('Pause Timer') %>" /></a>
             <a href="#" class="submit-time"><img src="<% RT->Config->Get('WebPath') %>/static/images/submit.png" alt="<% loc('Submit Timer') %>" title="<% loc('Submit Timer') %>" /></a>
             <a href="#" class="close-popup hidden"><img src="<% RT->Config->Get('WebPath') %>/static/images/close.png" alt="<% loc('Close Window') %>" title="<% loc('Close Window') %>" /></a>
         </div>
     </div>
 
-    <div class="extra"><&|/l, $Now->AsString &>Started at [_1].</&></div>
+    <div class="extra"><&|/l, $now->AsString &>Started at [_1].</&></div>
 
 % if ($Ticket->TimeEstimated) {
     <div class="extra"><&|/l&>Time estimated</&>: <& /Ticket/Elements/ShowTime, minutes => $Ticket->TimeEstimated &></div>
diff --git a/share/html/Ticket/Create.html b/share/html/Ticket/Create.html
index e396857..8357af2 100644
--- a/share/html/Ticket/Create.html
+++ b/share/html/Ticket/Create.html
@@ -121,7 +121,6 @@
           CustomFields => $QueueObj->TicketCustomFields,
           Grouping => 'Basics',
           InTable => 1,
-          ForCreation => 1,
       &>
       <& /Ticket/Elements/EditTransactionCustomFields, %ARGS, QueueObj => $QueueObj, InTable => 1 &>
     </table>
@@ -135,7 +134,6 @@
     %ARGS,
     Object => $ticket,
     CustomFieldGenerator => sub { $QueueObj->TicketCustomFields },
-    ForCreation => 1,
 &>
 
 </div>
@@ -212,7 +210,6 @@
     CustomFields => $QueueObj->TicketCustomFields,
     Grouping => 'People',
     InTable => 1,
-    ForCreation => 1,
 &>
 
 <tr>
@@ -307,7 +304,6 @@
     CustomFields => $QueueObj->TicketCustomFields,
     Grouping => 'Dates',
     InTable => 1,
-    ForCreation => 1,
 &>
 </table>
 </&>
diff --git a/share/html/Ticket/Elements/AddAttachments b/share/html/Ticket/Elements/AddAttachments
index a271c3c..32217c1 100644
--- a/share/html/Ticket/Elements/AddAttachments
+++ b/share/html/Ticket/Elements/AddAttachments
@@ -163,17 +163,25 @@ jQuery( function() {
         </div>
     </td>
 </tr>
-% if ($HasExisting) {
+% if (@quoted_attachments) {
 <tr>
   <td class="label" valign="top"><&|/l&>Include attachments</&>:</td>
   <td id="reuse-attachments">
-    <& /Ticket/Elements/ShowAttachments,
-      Ticket       => $TicketObj,
-      Selectable   => 1,
-      HideTitleBox => 1,
-      Checked      => \@AttachExisting,
-      Count        => 5,
-    &>
+%     for my $attach (@quoted_attachments) {
+    <label>
+      <input type="checkbox" class="checkbox" name="AttachExisting" value="<% $attach->Id %>" \
+             <% (grep { $attach->Id == $_ } @AttachExisting) ? 'checked' : '' %> />
+      <% $attach->Filename %>
+      <% loc("[_1] ([_2]) by [_3]", $attach->CreatedAsString, $attach->FriendlyContentLength, $m->scomp('/Elements/ShowUser', User => $attach->CreatorObj)) |n %>
+    </label>
+<%perl>
+my $url = RT->System->ExternalStorageURLFor($attach) || sprintf '%s/Ticket/Attachment/%d/%d/%s',
+            RT->Config->Get('WebPath'), $attach->TransactionObj->Id, $attach->Id,
+            $m->interp->apply_escapes($attach->Filename, 'u');
+</%perl>
+      (<a href="<% $url %>" target="_blank"><&|/l&>View</&></a>)
+      <br />
+%     }
   </td>
 </tr>
 % }
@@ -190,15 +198,10 @@ if ( exists $session{'Attachments'}{ $Token } && keys %{ $session{'Attachments'}
     $attachments = $session{'Attachments'}{ $Token };
 }
 
-my $HasExisting = 0;
-
-if ($TicketObj && $TicketObj->id) {
-    my $Existing = $TicketObj->Attachments;
-    $Existing->Limit(
-        FIELD    => 'Filename',
-        OPERATOR => '!=',
-        VALUE    => '',
-    );
-    $HasExisting = 1 if $Existing->Count;
+my @quoted_attachments;
+if ($TicketObj and $TicketObj->id) {
+    @quoted_attachments = sort { lc($a->Filename) cmp lc($b->Filename) }
+                          grep { defined $_->Filename and length $_->Filename }
+                            @{$TicketObj->Attachments->ItemsArrayRef};
 }
 </%INIT>
diff --git a/share/html/Ticket/Elements/ShowAttachments b/share/html/Ticket/Elements/ShowAttachments
index ac663a9..f32ac9c 100644
--- a/share/html/Ticket/Elements/ShowAttachments
+++ b/share/html/Ticket/Elements/ShowAttachments
@@ -49,25 +49,15 @@
 <&| /Widgets/TitleBox, title => loc('Attachments'), 
         title_class=> 'inverse',  
         class => 'ticket-info-attachments',
-        color => "#336699",
-        hide_chrome => $HideTitleBox &>
-
-<div class="attachment-list">
+        color => "#336699" &>
 
 % foreach my $key (sort { lc($a) cmp lc($b) } keys %documents) {
 
 <%$key%><br />
-<ul <% $Selectable ? 'class="selectable"' : '' |n %> >
+<ul>
 % foreach my $rev (@{$documents{$key}}) {
 % if ($rev->ContentLength) {
-<li>
-
-% if ($Selectable) {
-    <label>
-    <input type="checkbox" class="checkbox" name="AttachExisting" value="<% $rev->Id %>" \
-             <% $is_checked{$rev->Id} ? 'checked' : '' %> />
-% }
-
+<li><font size="-2">
 % if (my $url = RT->System->ExternalStorageURLFor($rev)) {
 <a href="<%$url%>">
 % } else {
@@ -76,46 +66,12 @@
 % my $desc = loc("[_1] ([_2]) by [_3]", $rev->CreatedAsString, $rev->FriendlyContentLength, $m->scomp('/Elements/ShowUser', User => $rev->CreatorObj));
 <% $desc |n%>
 </a>
-
-% if ($Selectable) {
-    </label>
-% }
-
-</li>
+</font></li>
 % }
 % }
 </ul>
 
 % }
-
-% if ($show_more) {
-<span class="show-more-link">
-% my %params = %ARGS;
-% delete $params{Ticket};
-% delete $params{Attachments};
-% delete $params{Count};
-% my $query = $m->comp('/Elements/QueryString', %params, id => $Ticket->id );
-% my $url   = RT->Config->Get('WebPath')."/Helpers/TicketAttachments?$query";
-
-<script type="text/javascript">
-    function showAllAttachments(node) {
-        var container = node.closest('.attachment-list');
-        var params = node.closest('form').find('input[name=AttachExisting]').serialize();
-
-        node.parent().text(<% loc('Loading...') | n,j%>);
-
-        var url = <% $url |n,j %>;
-        if (params) url += '&' + params;
-        container.load(url);
-    }
-</script>
-
-<a href="#" onclick="showAllAttachments(jQuery(this)); return false;" ><% loc('Show all attachments') %></a>
-
-</span>
-% }
-
-</div>
 </&>
 
 % }
@@ -126,45 +82,18 @@
 # then we need to find one
 $Attachments ||= $Ticket->Attachments;
 
-# Avoid applying limits to this collection that may be used elsewhere
-# (e.g. transaction display)
-$Attachments = $Attachments->Clone;
-
-# Remember, each message in a transaction is an attachment; we only
-# want named attachments (real files)
-$Attachments->Limit(
-    FIELD    => 'Filename',
-    OPERATOR => '!=',
-    VALUE    => '',
-);
-
-my $show_more = 0;
+# XXX PERF: why doesn't this Limit on Filename to avoid fetching *all* the
+# attachments?
 my %documents;
-
-# show newest first
-$Attachments->OrderByCols(
-    { FIELD => 'Created', ORDER => 'DESC' },
-    { FIELD => 'id',      ORDER => 'DESC' },
-);
-
 while ( my $attach = $Attachments->Next() ) {
-   # display "show more" only when there will be more attachments
-   if (defined($Count) && --$Count < 0) {
-       $show_more = 1;
-       last;
-   }
-   push @{ $documents{ $attach->Filename } }, $attach;
+    next unless defined $attach->Filename && length $attach->Filename;
+   unshift( @{ $documents{ $attach->Filename } }, $attach );
 }
 
-my %is_checked = map { $_ => 1 } @Checked;
 </%INIT>
 <%ARGS>
 $Ticket => undef
 $Attachments => undef
 $DisplayPath => $session{'CurrentUser'}->Privileged ? 'Ticket' : 'SelfService'
-$HideTitleBox => 0
-$Selectable => 0
-$Count => undef
- at Checked => ()
 </%ARGS>
 
diff --git a/share/html/Ticket/Elements/ShowSummary b/share/html/Ticket/Elements/ShowSummary
index 4183dab..f891631 100644
--- a/share/html/Ticket/Elements/ShowSummary
+++ b/share/html/Ticket/Elements/ShowSummary
@@ -64,7 +64,7 @@
         class => 'ticket-info-people',
     &><& /Ticket/Elements/ShowPeople, Ticket => $Ticket &></&>
 % $m->callback( %ARGS, CallbackName => 'AfterPeople' );
-    <& /Ticket/Elements/ShowAttachments, Ticket => $Ticket, Attachments => $Attachments, Count => 5 &>
+    <& /Ticket/Elements/ShowAttachments, Ticket => $Ticket, Attachments => $Attachments &>
 % $m->callback( %ARGS, CallbackName => 'AfterAttachments' );
     <& /Ticket/Elements/ShowRequestor, Ticket => $Ticket &>
 % $m->callback( %ARGS, CallbackName => 'LeftColumn' );
diff --git a/share/html/Widgets/TitleBox b/share/html/Widgets/TitleBox
index 7c65082..822170c 100644
--- a/share/html/Widgets/TitleBox
+++ b/share/html/Widgets/TitleBox
@@ -46,16 +46,11 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 <div class="<% $class %>">
-% if ($hide_chrome) {
-  <% $content | n %>
-% } else {
   <& TitleBoxStart, %ARGS &><% $content | n %><& TitleBoxEnd &>
-% }
 </div>
 <%ARGS>
 $class => ''
 $hide_empty => 0
-$hide_chrome => 0
 </%ARGS>
 <%INIT>
 my $content = $m->content;
diff --git a/share/static/css/base/forms.css b/share/static/css/base/forms.css
index 2584ee0..9f57331 100644
--- a/share/static/css/base/forms.css
+++ b/share/static/css/base/forms.css
@@ -251,23 +251,6 @@ form div.submit div.buttons div.next {
     display: none;
 }
 
-ul.selectable {
-    list-style-type: none;
-}
-
-ul.selectable input[type=checkbox],
-ul.selectable a {
-    vertical-align: bottom;
-}
-
-#reuse-attachments {
-    padding-top: 0.25em;
-}
-
-.ticket-info-attachments ul li {
-    font-size: .8em;
-}
-
 /* query builder */
 
 #formatbuttons {
diff --git a/share/static/js/util.js b/share/static/js/util.js
index 93db1b8..45b3948 100644
--- a/share/static/js/util.js
+++ b/share/static/js/util.js
@@ -99,7 +99,7 @@ function setCheckbox(input, name, val) {
         name = input.name || input.attr('name');
         is_set_event = true;
     }
-    else if (input.name) {
+    else {
         var allfield = jQuery('input[name=' + input.name + ']');
         allfield.prop('checked', val);
     }
diff --git a/t/web/signatures.t b/t/web/signatures.t
index 7151efd..93e6464 100644
--- a/t/web/signatures.t
+++ b/t/web/signatures.t
@@ -4,6 +4,11 @@ use warnings;
 use RT::Test tests => undef;
 use HTML::Entities qw/decode_entities/;
 
+{
+    no warnings 'redefine';
+    *RT::Transaction::QuoteHeader = sub { "Someone wrote:" };
+}
+
 my ($baseurl, $m) = RT::Test->started_ok;
 ok( $m->login, 'logged in' );
 
@@ -47,11 +52,12 @@ sub template_is {
 
     # For ease of interpretation, replace blank lines with dots, and
     # put a $ after trailing whitespace.
-    # Remove the timestamp from the quote header
     my $display = $value;
     $display =~ s/^$/./mg;
     $display =~ s/([ ]+)$/$1\$/mg;
-    $display =~ s/On \w\w\w \w\w\w \d\d \d\d:\d\d:\d\d \d\d\d\d, \w+:/Someone wrote:/
+
+    # Remove the timestamp from the quote header
+    $display =~ s/On \w\w\w \w\w\w+ \d\d \d\d:\d\d:\d\d \d\d\d\d, \w+ wrote:/Someone wrote:/;
 
     is($display, $expected, "Content matches expected");
 

-----------------------------------------------------------------------


More information about the rt-commit mailing list