[SearchBuilder-devel] [RFC][PATCH] Pages fixes and tests for it functionality

Jesse Vincent jesse at bestpractical.com
Wed Jul 27 10:25:14 EDT 2005


So,  the only thing that I'm not really sure about is starting with row  
zero, rather than row 1, at least from a first read of this code.

I'm willing to be swayed by an argument, though.

At this point, do you want to see this in Jifty::DBI (aka the 2.0) or  
SB?

I'm sorry for the delay in my reply. This just got buried under another  
950 messages.

Jesse

On Jun 9, 2005, at 10:47 PM, Ruslan U. Zakirov wrote:

> Require comments and review.
> All tests pass for SQLite, MySQL and PostgreSQL.
>
>  r1777 at cubic-pc:  cubic | 2005-06-10 00:51:48 +0400
>
>  fix pages+count handling
>  now count returns correct values
>  some tests still fails because of GotoPage doesnt overlap like  
> NextPage
>  need overview how nice it works
>  r1778 at cubic-pc:  cubic | 2005-06-10 06:43:33 +0400
>   new tests for pages support
>  change FirstRow arg handling to consistent state with other indexies
>
> === t/01searches.t
> ==================================================================
> --- t/01searches.t  (revision 1765)
> +++ t/01searches.t  (patch sb_pages level 1)
> @@ -8,7 +8,7 @@
>  BEGIN { require "t/utils.pl" }
>  our (@AvailableDrivers);
>
> -use constant TESTS_PER_DRIVER => 55;
> +use constant TESTS_PER_DRIVER => 104;
>
>  my $total = scalar(@AvailableDrivers) * TESTS_PER_DRIVER;
>  plan tests => $total;
> @@ -39,6 +39,7 @@
>  # check that new object returns 0 records in any case
>  	is( $users_obj->_RecordCount, 0, '_RecordCount returns 0 on not  
> limited obj' );
>  	is( $users_obj->Count, 0, 'Count returns 0 on not limited obj' );
> +	is( $users_obj->CountAll, 0, 'CountAll returns 0 on not limited obj'  
> );
>  	is( $users_obj->IsLast, undef, 'IsLast returns undef on not limited  
> obj after Count' );
>  	is( $users_obj->First, undef, 'First returns undef on not limited  
> obj' );
>  	is( $users_obj->IsLast, undef, 'IsLast returns undef on not limited  
> obj after First' );
> @@ -57,6 +58,7 @@
>  # unlimit new object and check
>  	$users_obj->UnLimit;
>  	is( $users_obj->Count, $count_all, 'Count returns same number of  
> records as was inserted' );
> +	is( $users_obj->CountAll, $count_all, 'CountAll returns same number  
> of records as was inserted' );
>  	isa_ok( $users_obj->First, 'DBIx::SearchBuilder::Record', 'First  
> returns record object' );
>  	isa_ok( $users_obj->Last, 'DBIx::SearchBuilder::Record', 'Last  
> returns record object' );
>  	$users_obj->GotoFirstItem;
> @@ -144,7 +146,117 @@
>  	$users_obj->Limit( FIELD => 'Phone', OPERATOR => 'IS NOT', VALUE =>  
> 'NULL', QOUTEVALUE => 0 );
>  	is( $users_obj->Count, $count_all - 2, "found users who has phone  
> number filled" );
>
> +# pages
> +	# Count before fetchrow
> +	$users_obj->CleanSlate;
> +	is_deeply( $users_obj, $clean_obj, 'after CleanSlate looks like new  
> object');
> +	$users_obj->UnLimit;
> +	is( $users_obj->RowsPerPage( 3 ), 3, "RowsPerPage returns current  
> value" );
> +	is( $users_obj->Count, 3, 'Count returns number of records on the  
> current page' );
> +	is( $users_obj->CountAll, $count_all, 'CountAll returns number of  
> records in the whole set' );
>
> +	# Count after fetchrow
> +	$users_obj->CleanSlate;
> +	is_deeply( $users_obj, $clean_obj, 'after CleanSlate looks like new  
> object');
> +	$users_obj->UnLimit;
> +	is( $users_obj->RowsPerPage( 3 ), 3, "RowsPerPage returns current  
> value" );
> +	$users_obj->Next;
> +	is( $users_obj->Count, 3, 'Count returns number of records on the  
> current page' );
> +	is( $users_obj->CountAll, $count_all, 'CountAll returns number of  
> records in the whole set' );
> +
> +	# check that we dont do new search after call to RowsPerPage with  
> the same arg
> +	is( $users_obj->RowsPerPage( 3 ), 3, "RowsPerPage returns current  
> value" );
> +	ok( !$users_obj->{'must_redo_search'}, "no same search redo" );
> +	$users_obj->FirstRow( $users_obj->FirstRow );
> +	ok( !$users_obj->{'must_redo_search'}, "no same search redo" );
> +
> +	# some FirstRow sanity checks
> +	$users_obj->CleanSlate;
> +	is_deeply( $users_obj, $clean_obj, 'after CleanSlate looks like new  
> object' );
> +	$users_obj->UnLimit;
> +	is( $users_obj->FirstRow, 0, "default FirstRow value is zero" );
> +	$users_obj->FirstRow( 1 );
> +	is( $users_obj->FirstRow, 1, "RirstRow returns value we set" );
> +
> +	# walk pages
> +	$users_obj->CleanSlate;
> +	is_deeply( $users_obj, $clean_obj, 'after CleanSlate looks like new  
> object' );
> +	$users_obj->UnLimit;
> +	is( $users_obj->RowsPerPage( 3 ), 3, "RowsPerPage returns current  
> value" );
> +	my ($counter, $pages, @layout) = (0, 0);
> +	while(1) {
> +		last unless $users_obj->Count;
> +		ok( $users_obj->Count >= 1, "page has at least one record");
> +		ok( $users_obj->Count <= 3, "page has at most three records");
> +		is( $users_obj->CountAll, $count_all, "CountAll dosn't change  
> behaviour with pages");
> +		$layout[$pages] = [];
> +		while( my $rec = $users_obj->Next ) {
> +			push @{ $layout[$pages] }, $rec->id;
> +			$counter++;
> +		}
> +		$pages++;
> +		$users_obj->NextPage;
> +	}
> +	is( $pages, 2, 'two pages' );
> +	# page support has bug by design, pages overlaps by one record
> +	is( $counter, $count_all, 'walk through all records' );
> +
> +	# check GotoPage
> +	for( my $i = 0; $i < $pages; $i++ ) {
> +		$users_obj->GotoPage($i);
> +		is( $users_obj->Count, scalar @{$layout[$i]}, "GotoPage walks  
> through the same pages");
> +		$counter = 0;
> +		while( my $rec = $users_obj->Next ) {
> +			is( $rec->id, $layout[$i]->[$counter], "the same record");
> +			$counter++;
> +		}
> +	}
> +
> +	# FirstPage check
> +	$users_obj->FirstPage;
> +	{
> +		is( $users_obj->Count, scalar @{$layout[0]}, "Count counts only  
> first page");
> +		$counter = 0;
> +		while( my $rec = $users_obj->Next ) {
> +			is( $rec->id, $layout[0]->[$counter], "the same record");
> +			$counter++;
> +		}
> +	}
> +
> +	# PrevPage
> +	$users_obj->GotoPage(2); # Jump to third page and walk back
> +	{ my $page = 2;
> +	do {
> +		$users_obj->PrevPage;
> +		$page--;
> +		$counter = 0;
> +		while( my $rec = $users_obj->Next ) {
> +			is( $rec->id, $layout[$page]->[$counter], "the same record");
> +			$counter++;
> +		}
> +	} while $users_obj->FirstRow != 0; }
> +
> +	# check that GotoPage&Co do nothing if we dont use pages
> +	$users_obj->CleanSlate;
> +	is_deeply( $users_obj, $clean_obj, 'after CleanSlate looks like new  
> object' );
> +	$users_obj->UnLimit;
> +	$users_obj->GotoPage(2);
> +	is( $users_obj->FirstRow, 0, "FirstRow is always O if don't use  
> pages");
> +	is( $users_obj->RowsPerPage, 0, "RowsPerPage is always O if don't  
> use pages");
> +	$users_obj->PrevPage;
> +	is( $users_obj->FirstRow, 0, "FirstRow is always O if don't use  
> pages");
> +	is( $users_obj->RowsPerPage, 0, "RowsPerPage is always O if don't  
> use pages");
> +	$users_obj->NextPage;
> +	is( $users_obj->FirstRow, 0, "FirstRow is always O if don't use  
> pages");
> +	is( $users_obj->RowsPerPage, 0, "RowsPerPage is always O if don't  
> use pages");
> +	$users_obj->FirstPage;
> +	is( $users_obj->FirstRow, 0, "FirstRow is always O if don't use  
> pages");
> +	is( $users_obj->RowsPerPage, 0, "RowsPerPage is always O if don't  
> use pages");
> +
> +
> +	
> +
> +
>  	cleanup_schema( 'TestApp', $handle );
>  }} # SKIP, foreach blocks
>
> === t/01records.t
> ==================================================================
> --- t/01records.t  (revision 1765)
> +++ t/01records.t  (patch sb_pages level 1)
> @@ -170,7 +170,7 @@
>  	ok( $id, "new record");
>  	$rec = TestApp::Address->new($handle);
>  	$rec->LoadByCols( Name => 'Obra', Phone => undef, EmployeeId => '' );
> -    is( $rec->id, $id, "loaded record by empty value" );
> +	is( $rec->id, $id, "loaded record by empty value" );
>
>  # __Set error paths
>  	$rec = TestApp::Address->new($handle);
> === SearchBuilder.pm
> ==================================================================
> --- SearchBuilder.pm  (revision 1765)
> +++ SearchBuilder.pm  (patch sb_pages level 1)
> @@ -138,7 +138,6 @@
>      $self->{'order'}            = "";
>      $self->{'alias_count'}      = 0;
>      $self->{'first_row'}        = 0;
> -    $self->{'must_redo_search'} = 1;
>      $self->{'show_rows'}        = 0;
>      @{ $self->{'aliases'} } = ();
>
> @@ -195,6 +194,7 @@
>
>      # If we're about to redo the search, we need an empty set of items
>      delete $self->{'items'};
> +    $self->{'raw_rows'} = 0;
>
>      my $records = $self->_Handle->SimpleQuery($QueryString);
>      return 0 unless $records;
> @@ -223,6 +223,7 @@
>      my $self = shift;
>      my $record = shift;
>      push @{$self->{'items'}}, $record;
> +    $self->{'raw_rows'}++;
>  }
>
>  =head2 _RecordCount
> @@ -260,7 +261,7 @@
>      my @row = $records->fetchrow_array();
>      return 0 if $records->err;
>
> -    $self->{ $all ? 'count_all' : 'raw_rows' } = $row[0];
> +    $self->{ $all? 'count_all' : 'raw_rows' } = $row[0];
>
>      return ( $row[0] );
>  }
> @@ -629,6 +630,7 @@
>  sub RedoSearch {
>      my $self = shift;
>      $self->{'must_redo_search'} = 1;
> +    delete $self->{'raw_rows'} if $self->RowsPerPage;
>  }
>
>  # }}}
> @@ -1312,7 +1314,7 @@
>  # {{{ sub FirstPage
>  sub FirstPage {
>      my $self = shift;
> -    $self->FirstRow(1);
> +    $self->FirstRow(0);
>  }
>
>  # }}}
> @@ -1325,11 +1327,11 @@
>
>  sub PrevPage {
>      my $self = shift;
> -    if ( ( $self->FirstRow - $self->RowsPerPage ) > 1 ) {
> +    if ( ( $self->FirstRow - $self->RowsPerPage ) > 0 ) {
>          $self->FirstRow( $self->FirstRow - $self->RowsPerPage );
>      }
>      else {
> -        $self->FirstRow(1);
> +        $self->FirstRow(0);
>      }
>  }
>
> @@ -1342,9 +1344,9 @@
>      my $page = shift;
>
>      if ( $self->RowsPerPage ) {
> -    	$self->FirstRow( 1 + ( $self->RowsPerPage * $page ) );
> +    	$self->FirstRow( $self->RowsPerPage * $page );
>      } else {
> -        $self->FirstRow(1);
> +        $self->FirstRow(0);
>      }
>  }
>
> @@ -1362,7 +1364,10 @@
>
>  sub RowsPerPage {
>      my $self = shift;
> -    $self->{'show_rows'} = shift if (@_);
> +    if( @_ && $self->{'show_rows'} != $_[0]) {
> +	$self->{'show_rows'} = shift;
> +	$self->RedoSearch;
> +    }
>
>      return ( $self->{'show_rows'} );
>  }
> @@ -1384,11 +1389,12 @@
>  sub FirstRow {
>      my $self = shift;
>      if (@_) {
> -        $self->{'first_row'} = shift;
> +    	my $row = int shift;
>
> -        #SQL starts counting at 0
> -        $self->{'first_row'}--;
> +	return ($self->{'first_row'}) if $self->{'first_row'} == $row;
>
> +        $self->{'first_row'} = $row;
> +
>          #gotta redo the search if changing pages
>          $self->RedoSearch();
>      }
> @@ -1435,10 +1441,13 @@
>
>      # If we haven't actually got all objects loaded in memory, we
>      # really just want to do a quick count from the database.
> -    if ( $self->{'must_redo_search'} ) {
> +    if ( $self->{'must_redo_search'} || !defined $self->{'raw_rows'}  
> ) {
>
> +    	# If we use pages then we should fetch records
> +	$self->_DoSearch if $self->RowsPerPage;
> +
>          # If we haven't already asked the database for the row count,  
> do that
> -        $self->_DoCount unless ( $self->{'raw_rows'} );
> +        $self->_DoCount unless defined $self->{'raw_rows'};
>
>          #Report back the raw # of rows in the database
>          return ( $self->{'raw_rows'} );
> @@ -1495,15 +1504,11 @@
>          # If we haven't already asked the database for the row count,  
> do that
>          $self->_DoCount(1) unless ( $self->{'count_all'} );
>
> -        #Report back the raw # of rows in the database
>          return ( $self->{'count_all'} );
>      }
>
> -    # If we have loaded everything from the DB we have an
> -    # accurate count already.
> -    else {
> -        return $self->_RecordCount;
> -    }
> +    # Report back the raw # of rows in the database
> +    return ( $self->{'count_all'} );
>  }
>
>  # }}}
>
> ==== BEGIN SVK PATCH BLOCK ====
> Version: svk 1.0_01 (linux)
>
> eJzlXM1vHEd2n/ 
> UhAJlccjCQHAKUqbFJShyqv7+0JChRkqPY1nJFOTkYyqSmu3qmrZ7ucXcPR4yG
> iKiNk02APSxyChJgFwmQLAIs4sMecg2w/ 
> 0cQLBAEuSS3XPNeVfd0z0xPDynb2DUiyOawu+rV732/
> V1Wjh8nTO0fy9PBQmrZlaXr6+x84zgnN3MG7sjZtG1PmBVmctPVpyM5Y2FanYdxva9OIDhm 
> 8TeNx
> 4uKHjCZ9luGHwH3OssNDGchZgtwDTqIgy6n2aBZHadvm5LtZwlhbnupHxvRIxb/ 
> dtmxPUwZvONlu
> ws6CNIgjWFg2TQtGwHAZpscjFnWTOM6KNwrOlaZuGKesi8SRoI7DlTYwxMd7QcJcQHQOTzN 
> OKJ/M
> x+kFWT8IAZUxPWU0cQf3xkHosWR/ 
> NKzO4FD1fLkqXXm2rjpPT5tmtyU55TRZup9xZNX1tfnxKh8P
> hOPEWxi+cnEFxADE+Fs6GoXn3Yy9yDwWZpQDUpWp6zNm6Apjmu0yi1k9RdGZaRmaKauGLtG 
> 2amoK
> qO9xq/Wv0188Ov7b77Qud1vfa31/4/LWj1v9v7zd+v5v/kXy09bf/84PP/xx6+wnf/ 
> Lq9Rb/8fmv
> t3z4cfk+//GDX+M/ 
> PmetH7z9s74sacfxOMruhuEekfbIdvEbSVg2TqKUSDukPU5Zknbj3qedw3J0
> 28WPXYqfZ9NukBHts3Rz4wbhj0iP+XHCiM/A0JJ48nH0YTAMsjubG0E6T/ 
> hJPElPWHIC03eISnb3
> iLpHtipPZ4jccZIwIH1GwzHbIrs1xPjanIJANpsbjYc9lpDYJ7n+SByRbMBmRBH+9mqaqzl 
> vWCIQ
> S0wGccgI+BCnX4qI+hmM/ 
> 5olVCX0GEzvmys0cFL3ObyjGZkw4sWwvheTiE2IcOFcni6sRLKYVOUz
> CbIBp5pCrCQQyL5iIcfPd8g7VWovt4fjFIOlF3cFuu0LIBfFAkEOGF8va+lhkKQZLDyPr3j 
> 6layH
> 4kxjeDGjmtIoyM6FjNMlSKttsyDAg8iWx3w6DrOSLJcRCVLyxyxpZFWutaKSuozKKKgWmhD 
> UJ9xM
> ZnxNaPhcBKNrsPGltD88JzvCylkC9s7X3iNHIT2Px9kuOSA7IBsJR04GkEh25F3ycnNjI6R 
> pRsZR
> yNJ02XVgMNfy0gtyeMCFgauQAU0JuEPIkFQcsdyJtnZXT//2AWetOn0Yw+xsAJm/ 
> cEJB4Go+vTXz
> aS9Oo+0MbIhGQLzHBvQsgKJEeB+XiqDbFpL5REjqGQjok2f4XEiHgDjbgAMeL8YuIgS3MRq 
> nA3L0
> kiwSApPHmZ3DwEN6G4VSbt3CXy9waT5S/ 
> L5IHdUMzy9y68jVqEDUyiaxwC9inch1JB2PRnGScSn2
> xn3SOyceS4N+tJebX3zGkpCOUnxTKicnX9pLNT5y4wVVxOM+xDMeJ7lCFoLg+3EWI9zNDUi 
> yQmIB
> yEu6gz+/ 
> nWPHX27dymVWZbaYvdMOVut5j6QQSWkCcp6JOXiGQaWYzj0tnaGdhdeqpnMuObbraJhD
> ylW5RyoAOoefFESfAZbZolXDX9b7BZcdjyYcOZdiTSjKTeDlNYQicZkI3+LLYpIMz4mP9Lg 
> svhZR
> SF9KEidQxQv7qbULZfcOuUF+bzwcYSLNBkHiCZOnkSfia4+i/ 
> F5y+PzNAVFgBcjHi8ZWLHWn8L5O
> 5+uwDKT8piIhfPH6bPsO96qLxQKkENV7xzEvQmIQUtQngT8rTYDY2iy0Svjr0uwMHSRWGk7 
> oeUq+
> g2vDwtuVlbfqKFVymiBWTXJXoLdCt98MwJUw/ 
> 80AXI1Kv7KIwTmOtGqzL9rlvLulumFaptSTdUlV
> fdmwZFfRJIOZtm5pktnYH2tIwVMt3VRt6lqGaym+p1FdNa2e7PdM17Bts63k3fHPf+vnb29 
> +q/XF
> jdZl668++2K7HhWnaRo9WbZd6kuWx1TfUxVPpqpi2LJFVVdmjah0pCBpvutJkq4CBcuSNNo 
> DAqrL
> 4BfqyYrZthVVwHr9Dx+//slb7p/dbP3orVbrz50fbf+09d1/Pmh97+Af7/116/PBP120/ 
> uU3vvB/
> 1vrft/5zdNm6fPvy39JXn7Uuf/vy389f3W+97lz+4g9fua3Xw8v/kF69bH3+7PK/ 
> Wq8uv9WKL//7
> j/6m9cPbl//jv7pstf7u49d/ 
> 2iLwp52y0MeWIKGTLjSW6faFiLKb+DaPsLzVqh8MNQP8AWZZxmqJ
> gRXkjyt2Ikk8QpP8Tz6g0svMPyCdGhoYKnHyBf8/ 
> C8HIVlOUaubfzLNRQWctjcDfIUdd8t57JaPp
> IJ5xCtG/ 
> 3YVcy3NP7YgDkg4CnwfzHA70WGKbKsewwSUOHB9Aa5sVwzc3REMBnUNBllcMSHf7Yrci
> 47kX5OCAE8uVOafBuWF81HRK3oGWLIiYV6tIZIvTgeT2iKeuMmtB8ox4azWIx6EndimKanT 
> GbPd+
> zmu9TdxpWLxgv3w3q4MRWWEI/ 
> McN8oTxUhvLDl5oAh14irsGQKzYMvBoRns0ZXzOOvq1sUF4tmSZ
> lmr5mur1IOAohqz7lNmyJ/mKYcqMbzrKsiJJU5LIENyO3HEvcDsj1yGEfyRTAm/ 
> 1DvxVDCIpji45
> qkRuSZokbZIT0XpFXoglgx+8wDbDhR4uGkOvgCVWxtIs3QTipmmsJm50ZIlIkoP0jYI4IrL 
> KSWQn
> ToI+SRRbU3eBQh+aToj7VYAaUWRHMhzNntEgiapYlnyUBVHHj4Nw1URZdjT4K5FOMfFh8IL 
> 4STwk
> T8ZpSCNRPmIB1sM2F/l1Y4/ 
> tw9AcqlkHVWuEajqytgBVuRJU25H0CtQSpkOgjcKtKJaAfLPzEWpk
> SJ8zDp4NR8XOCDS1ZCsaQ18G46WtPSz8ygfb21szxmyrhjFTQsY+BUmwKjoTtSgrjmpV2AL 
> dK+bR
> YEzDgEV1swwiGygMTSl5ukkel9th3IqENhLOZgnOrgMnN4LT1AVw1npwlqNpCwIXSBz8Hf9 
> b3NAX
> 7vBe4Q1OEeWO8cFpSDOsrlkKcTSIAgymeSRePY6TIt2XuI8vnP2iO6IJi2Zz+iwjSeBhNEm 
> z8Qg+
> BT6PKRViNWPZGQ35sDIIou/Cb3mriLH0d9HNGRmybBBDwgV3cKE5SOKQ3L/ 
> 3iLAkAbOZhYJCP6Yk
> 1elHadaPvaAfe61+ZHSmqvHkTks9D2I2fEAZdzGq5gxwd749zoIw3R+FJVy5Bq5l1DuxKmN 
> A1BRH
> qVq7qmq22uzEEEBlsHbNUSoGf4+m4LHpc56dQCmn4KZD+j6LWEKzONkn5D6awTbfKnbjcDy 
> MUnLO
> shK7UofdbMSuQtRbwK6tx25hrJQr/ 
> nAs4OyRURIMaXJOnjMosidx8hytasbJfolVrcNqrcZqOLru
> SHPBUoUq/ 
> CjNQDpZDICDM9ZJ2RmLsvNVwBVILyB0uwQOlvIRBseUQwSf4NIO4ghtJh7hJxpCxUAh
> A+euc5OcJPFZ4DFC0cl6pPsI/ 
> Rf4vO84p47zRGyNiaHHYgPxKYWkcZ+lbhJwmmh9Qir5OIgVPEAH
> Kc3DM9C763kfQYrhRwDUzcAFwnN4nmY0ygJw5Xwu2DhxE4DIuhmukxKxTilsrU7Ydp0Poqh 
> NTKGS
> VPVBS5L1Bh9E0aqgnTnR3sw5zIP3hIEA8SOvFDDnkAnWZcD1OZkAR0z4JIzgr30ISaCNNC3 
> Z0GvY
> sKXVNgOM2I6sztuMbF/TZlQM/ 
> noluJyi0osdU4T65MHDB08ePD5+cFpiratbbLkJKyykLWBVlGtj
> hb9ypYjJwwcj3WOccNd1sXYBIxHJVGhoD0te0EMiOuTSMnNe6gob267jxehICpEgNgAQfb6 
> wMdbE
> RAiF4J6q6eiVmPgHSQzWQpM+1DOQAME+juMoYm7FtpeLE1WSao1iBk5zVHkB3JqgJ8DpgE8 
> twYF7
> kpM4zfoJuNwZS/AqQYqRGx0Zz/ 
> Ly2rdAulypANJakyiQKsZ8IYVIjfVIVUc1HKVisVhJ5THMIe0B
> tFSQsl9AtKqWLI4jMnznELDfmfVks95sgBvHXPg75H4C1piQg0OyfdLf3iP7+/ 
> t5n7NBRJcTQZcI
> K2E8a1jLcU76MwHJy6UCCEhpFJCJ1j4vIHONgFReZUCvUYlV92M3t7BcdduiZAYFbmOQ9/ 
> 09XhFh
> qKXg73fvf/ 
> Rgn+zchUfjkYf+5cajc4A84EaKa+3vlowtFxXAWG0TUzCmQUmzoHlTX8uYbPMgbMwx
> VrRliD9hPsXrHNi+x0RkKl7ilViXiwjAWtvFVLDqC0ow11mpilYKpZ5cwXoXbHRChnjVwgP 
> Y4uyt
> 9B95uWQAZHojMttRlQVk68xDK8zDKpHxK0bVZjAv5m+CQCdJAOr/ 
> MKbevfMTUf18gMUPBK20rIdF
> tZwGaYZWxk8RY4y4fOJNQS2vrEvSPMGIwpqnypMPCDb3HkbpYSB6UCgTltYuKGBRMaFJlI/ 
> rdk+h
> 5C/ 
> qd04RTH12rD2OPOYXU9Mhnthhgztr54tXPEO7eCCIzX+f71pw0Zj6vvIucmpp++a7IjNyC4 
> Nm
> qNTichIHLdYWqYUWdWkpmfzqdcmmvJzxgbHairbCmDZnnqqirUtEJnYOqox5oSxiYaasSGW 
> tEEes
> w/BmXbS2YRfdkzJP7w1b9is07aJVFoDlNYDrm/gCsKYuAb52G7/cyOf4rtzMX72df7OG/ 
> not/dff
> 1Ff1p6zRX32TP9OfvaS/a7f5b9ToCxZKv12ubsFvG6tbXV1Izr+sjl+uK37lhuJXcTC5/ 
> VI6frmu
> /JUbyl/AKmP8Xuz412H9f9rkK3XVs9xQPXP5KtJSd7xWvm/ 
> UECt1daXcUFdyePq8qRpaIzyYKBNo
> PcHNtErev5fQCBzsmEuPK+n0ux+KChiUC4ENeh48E+30wriXH7ZguMvjB6/ 
> 7SQilWyf2O6CXjGGr
> wEO0GFIauVqnBKVZCTp2vAWXOZm6hkFpaBgU3LIpj2UKMnUyV5plbkA5v0imrvBWGgpvhR9 
> sLJGp
> K5CUhgIJugMMmd8wC6hLJ0pDOgEuwZsWuLQaez3BJZSBMFeZLwM1u+xvrrCBLSI738CuJuM 
> 3TWhf
> KqUt5GW1LrepjbkN2t+F3Ww8P7yKILUaQVp1gly1my4EyXfTFwX5Jtn1Wvl1UXB1iVZtTLS 
> KtHAO
> qeJp5lUEhyXZvOB0SasT3KqtfZGv+db+vOC+is39N8n818r9V8/+Xy7/ 
> r6kAFixAq8tCamMWAgtQ
> 1QULsK5kARbkjAULgFKkxgLqzxtEPcHPG+bagTc5cfhKzxwWZVqXktXGlKzI1SSIksFNgrU 
> ytbDL
> qWavEkNdPlcb8zlg0MwFDFfwbI6huhFfYqgrBtTGYgAcc+HgzqxYSBMGZc4sSgzL51mAoTb 
> HVTAs
> lLqm0ngppIJBrpVD3T6W2rCPxTGo+gKGxn2sKga1DkNdRaU2VlToNItyaExQMwzm3LnSaZx 
> ATqK9
> eJzxu/0Y1obUQ9/ZJ4/ 
> wnnX0nEC8Ts7z28Qp6cdQSkXxpKyVtLoUb6xK8SoBdwezVOZtyVLX6VHB
> OCWpc5VKP85I51CudCo8twLUEl1dHjVW5dECnbaIbp2GOTrdnLt69IRRD6XG76gnQZbvIO9 
> EmArj
> hAX9aBf38iG8RS4DifON1j5kKUw8UHblgzpQYYXMxafpHhLujTOx9yQKMBrl6im+VFbu0+p 
> 18c5Y
> ZVsaL/ 
> qthYtXqqWtizUqkTU8kJMrYRzP1fhppeOI80qIzPjtHiiFgOHPxM30bX5KgNjL3F6CrwuU
> xqoiXIC38UBoHvy6BAjgddxkrjoGpKD8S0M0/95fbxyJWrid9vDuHk/ 
> e2xeoUP6EFw751IfAqshg
> uEEf8GuKhZaBYK5WUqo137XOGxUxRRQJeO0RvK4cWllC3H3swDiPsFA0M3tYjHQORY+Eu4D 
> gvJnY
> vY17nyLawCM7n44hVYYBLMlHn7LsYRzv5qTDGHIuP78R6Zd/ 
> E7KED8ZcscdSWXXR3NSWqwWQuIFV
> nqLPb5vLNihrZa3AZ4GFQeTT524IPY4zVNIwiILheEieAmTH+YifPrERizxAfc6rgryA2Cd 
> PQbHP
> +Sbpk7lLaKZelwxMvYEFYz5QAAtQtK1lQZ+LYTf5FUWKxxfxDIpRI01ZqdlKB6I2AauHpkW 
> fuw9n
> 4+WFBig2P1lT5zbSbxJ5X5W6kspxiOueZSPsrLruqQOh2UbqJq+PxZfa+P3W2cbzJj9Ndue 
> +zwsG
> jN9MF99dBGPiXwEVZgfagozk0yBMSY+5FPe5wRRn3/XKN9/ 
> zr7QJay6+TQFLMSgK8d1ZwCZkAAtH
> gQvmnvEEkV9lbbgnK3gzUEKVinp2HYBblLiWnO+YbRYBY3afnCb9VSeHfPOhen4YgKG+CEA 
> CbWua
> 9rqc8uGhMhXfJPjAcZ7yf+vAcT6O8Mg+peG7xrStTUc0G7TVacLO4JfxOPDaqja9jUf1nbm 
> zj9t5
> c5Te5qTzfySgrRpTn7o2GLnZcXVfgmAoSx1q62qn5/dM2/ 
> YNnWnscFeZrlpP0WvXC2OXhnwZQ7/q
> Mm3zauOc9Qw6yN7/AS4qilU=
> ==== END SVK PATCH BLOCK ====
> _______________________________________________
> SearchBuilder-devel mailing list
> SearchBuilder-devel at bestpractical.com
> http://lists.bestpractical.com/cgi-bin/mailman/listinfo/searchbuilder- 
> devel



More information about the SearchBuilder-devel mailing list