def deleteDuplicateRecords(  fnames, fids = nil, options = nil, dbid = @dbid )
      num_deleted = 0
      if options and not options.is_a?( Hash )
         raise "deleteDuplicateRecords: 'options' parameter must be a Hash"
      else
         options = {}
         options[ "keeplastrecord" ] = true
         options[ "ignoreCase" ] = true
      end
      findDuplicateRecordIDs( fnames, fids, dbid, options[ "ignoreCase" ] ) { |dupeValues, recordIDs|
         if options[ "keeplastrecord" ]
           recordIDs[0..(recordIDs.length-2)].each{ |rid| num_deleted += 1 if deleteRecord( dbid, rid ) }
         elsif  options[ "keepfirstrecord" ]
           recordIDs[1..(recordIDs.length-1)].each{ |rid| num_deleted += 1 if deleteRecord( dbid, rid ) }
         end
      }
      num_deleted
   end
def deleteDuplicateRecords(  fnames, fids = nil, options = nil, dbid = @dbid )
      num_deleted = 0
      if options and not options.is_a?( Hash )
         raise "deleteDuplicateRecords: 'options' parameter must be a Hash"
      else
         options = {}
         options[ "keeplastrecord" ] = true
         options[ "ignoreCase" ] = true
      end
      findDuplicateRecordIDs( fnames, fids, dbid, options[ "ignoreCase" ] ) { |dupeValues, recordIDs|
         if options[ "keeplastrecord" ]
           recordIDs[0..(recordIDs.length-2)].each{ |rid| num_deleted += 1 if deleteRecord( dbid, rid ) }
         elsif  options[ "keepfirstrecord" ]
           recordIDs[1..(recordIDs.length-1)].each{ |rid| num_deleted += 1 if deleteRecord( dbid, rid ) }
         end
      }
      num_deleted
   end
Finds records with the same values in a specified
 list of fields and deletes all but the first or last duplicate record.
 The field list may be a list of field IDs or a list of field names.
 The 'options' parameter can be used to keep the oldest record instead of the
 newest record, and to control whether to ignore the case of field values when
 deciding which records are duplicates.  Returns the number of records deleted.