From e366ee18bcc90027f6309fab360aa6b55c63c041 Mon Sep 17 00:00:00 2001 From: Ryan Poplin Date: Thu, 29 Sep 2011 07:46:19 -0400 Subject: [PATCH 03/19] Adding ability to read in and make use of kmer quality tables during HMM evaluation --- .../walkers/recalibration/TableRecalibrationWalker.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/TableRecalibrationWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/TableRecalibrationWalker.java index 174e810c2..e04f5bc4b 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/TableRecalibrationWalker.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/recalibration/TableRecalibrationWalker.java @@ -170,9 +170,9 @@ public class TableRecalibrationWalker extends ReadWalker requestedCovariates = new ArrayList(); // List of covariates to be used in this calculation - private static final Pattern COMMENT_PATTERN = Pattern.compile("^#.*"); - private static final Pattern OLD_RECALIBRATOR_HEADER = Pattern.compile("^rg,.*"); - private static final Pattern COVARIATE_PATTERN = Pattern.compile("^ReadGroup,QualityScore,.*"); + public static final Pattern COMMENT_PATTERN = Pattern.compile("^#.*"); + public static final Pattern OLD_RECALIBRATOR_HEADER = Pattern.compile("^rg,.*"); + public static final Pattern COVARIATE_PATTERN = Pattern.compile("^ReadGroup,QualityScore,.*"); public static final String EOF_MARKER = "EOF"; private long numReadsWithMalformedColorSpace = 0; From 4086fa768fee77771fba45d6b9b0c4de000d17d0 Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Thu, 29 Sep 2011 12:18:18 -0400 Subject: [PATCH 05/19] Disabling all ReadClipperUnitTests --- .../sting/utils/clipreads/ReadClipperUnitTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/java/test/org/broadinstitute/sting/utils/clipreads/ReadClipperUnitTest.java b/public/java/test/org/broadinstitute/sting/utils/clipreads/ReadClipperUnitTest.java index 1415379db..d8695cf38 100644 --- a/public/java/test/org/broadinstitute/sting/utils/clipreads/ReadClipperUnitTest.java +++ b/public/java/test/org/broadinstitute/sting/utils/clipreads/ReadClipperUnitTest.java @@ -62,7 +62,7 @@ public class ReadClipperUnitTest extends BaseTest { readClipper = new ReadClipper(read); } - @Test + @Test ( enabled = false ) public void testHardClipBothEndsByReferenceCoordinates() { logger.warn("Executing testHardClipBothEndsByReferenceCoordinates"); @@ -76,7 +76,7 @@ public class ReadClipperUnitTest extends BaseTest { } - @Test + @Test ( enabled = false ) public void testHardClipByReadCoordinates() { logger.warn("Executing testHardClipByReadCoordinates"); @@ -109,7 +109,7 @@ public class ReadClipperUnitTest extends BaseTest { } - @Test + @Test ( enabled = false ) public void testHardClipByReferenceCoordinates() { logger.warn("Executing testHardClipByReferenceCoordinates"); @@ -142,7 +142,7 @@ public class ReadClipperUnitTest extends BaseTest { } - @Test + @Test ( enabled = false ) public void testHardClipByReferenceCoordinatesLeftTail() { logger.warn("Executing testHardClipByReferenceCoordinatesLeftTail"); @@ -163,7 +163,7 @@ public class ReadClipperUnitTest extends BaseTest { } - @Test + @Test ( enabled = false ) public void testHardClipByReferenceCoordinatesRightTail() { logger.warn("Executing testHardClipByReferenceCoordinatesRightTail"); @@ -184,7 +184,7 @@ public class ReadClipperUnitTest extends BaseTest { } - @Test + @Test ( enabled = false ) public void testHardClipLowQualEnds() { logger.warn("Executing testHardClipByReferenceCoordinates"); From a5e75cd14cf7a8b6d3c4c8271302468fc5f256b4 Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Thu, 29 Sep 2011 12:54:18 -0400 Subject: [PATCH 08/19] Outputting both consensus base qualities and counts The base qualities of a consensus reads are now the average quality of the bases forming the consensus base (most common base) and the consensus quality tag now carry an array with the counts of each base in the consensus. This should increase file size but improve calling sensitivity/specificity. --- .../java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java b/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java index e0a3a5a53..fcb3089cd 100755 --- a/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java +++ b/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java @@ -52,6 +52,7 @@ public class ReadUtils { // ---------------------------------------------------------------------------------------------------- public static final String REDUCED_READ_QUALITY_TAG = "RQ"; + public static final String REDUCED_READ_CONSENSUS_COUNTS_TAG = "CC"; public final static Integer getReducedReadQualityTagValue(final SAMRecord read) { return read.getIntegerAttribute(ReadUtils.REDUCED_READ_QUALITY_TAG); From 95082201579062be0d49a0f845177e85f6c99d71 Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Thu, 29 Sep 2011 15:36:49 -0400 Subject: [PATCH 09/19] fixed hard clipping both ends inside deletion If both ends of the interval falls within a deletion in the read then hardClipBothEnds would cut the right tail first including the entire deletion, then fail to cut the left tail because there would not be any bases there anymore. Fixed. --- .../broadinstitute/sting/utils/clipreads/ReadClipper.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/public/java/src/org/broadinstitute/sting/utils/clipreads/ReadClipper.java b/public/java/src/org/broadinstitute/sting/utils/clipreads/ReadClipper.java index 5230381c0..11a59de10 100644 --- a/public/java/src/org/broadinstitute/sting/utils/clipreads/ReadClipper.java +++ b/public/java/src/org/broadinstitute/sting/utils/clipreads/ReadClipper.java @@ -94,6 +94,12 @@ public class ReadClipper { if (left == right) return new SAMRecord(read.getHeader()); SAMRecord leftTailRead = hardClipByReferenceCoordinates(right, -1); + + // after clipping one tail, it is possible that the consequent hard clipping of adjacent deletions + // make the left cut index no longer part of the read. In that case, clip the read entirely. + if (left > leftTailRead.getAlignmentEnd()) + return new SAMRecord(read.getHeader()); + ReadClipper clipper = new ReadClipper(leftTailRead); return clipper.hardClipByReferenceCoordinatesLeftTail(left); } From 98ecaf8aa0c0507f3f6774cc3065604648e210d6 Mon Sep 17 00:00:00 2001 From: Mark DePristo Date: Thu, 29 Sep 2011 17:18:39 -0400 Subject: [PATCH 10/19] Support for ReducedReads with reduced counts and average quals -- ReadUtils and UnitTest updated to support new byte[] style -- Removed unnecessary read transformer in PairHMM --- .../indels/PairHMMIndelErrorModel.java | 4 --- .../sting/utils/pileup/PileupElement.java | 6 ++-- .../sting/utils/sam/ReadUtils.java | 33 ++++++++++++------- .../sting/utils/ReadUtilsUnitTest.java | 28 +++++----------- 4 files changed, 32 insertions(+), 39 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/indels/PairHMMIndelErrorModel.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/indels/PairHMMIndelErrorModel.java index c8328771b..7c436ce44 100755 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/indels/PairHMMIndelErrorModel.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/indels/PairHMMIndelErrorModel.java @@ -415,10 +415,6 @@ public class PairHMMIndelErrorModel { if (read == null) continue; - if ( isReduced ) { - read = ReadUtils.reducedReadWithReducedQuals(read); - } - if(ReadUtils.is454Read(read)) { continue; } diff --git a/public/java/src/org/broadinstitute/sting/utils/pileup/PileupElement.java b/public/java/src/org/broadinstitute/sting/utils/pileup/PileupElement.java index 053864791..f6ed792a5 100755 --- a/public/java/src/org/broadinstitute/sting/utils/pileup/PileupElement.java +++ b/public/java/src/org/broadinstitute/sting/utils/pileup/PileupElement.java @@ -87,11 +87,11 @@ public class PileupElement { public int getReducedCount() { if ( ! isReducedRead() ) throw new IllegalArgumentException("Cannot get reduced count for non-reduced read " + getRead().getReadName()); - return (int)getQual(); + return ReadUtils.getReducedCount(getRead(), offset); } public byte getReducedQual() { - return (byte)(int)ReadUtils.getReducedReadQualityTagValue(getRead()); + if ( ! isReducedRead() ) throw new IllegalArgumentException("Cannot get reduced qual for non-reduced read " + getRead().getReadName()); + return ReadUtils.getReducedQual(getRead(), offset); } - } \ No newline at end of file diff --git a/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java b/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java index fcb3089cd..a57154ff1 100755 --- a/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java +++ b/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java @@ -54,26 +54,35 @@ public class ReadUtils { public static final String REDUCED_READ_QUALITY_TAG = "RQ"; public static final String REDUCED_READ_CONSENSUS_COUNTS_TAG = "CC"; - public final static Integer getReducedReadQualityTagValue(final SAMRecord read) { - return read.getIntegerAttribute(ReadUtils.REDUCED_READ_QUALITY_TAG); + public final static byte[] getReducedReadQualityTagValue(final SAMRecord read) { + return read.getByteArrayAttribute(ReadUtils.REDUCED_READ_QUALITY_TAG); } public final static boolean isReducedRead(final SAMRecord read) { return getReducedReadQualityTagValue(read) != null; } + public final static byte getReducedQual(final SAMRecord read, final int i) { + return read.getBaseQualities()[i]; + } + + public final static byte getReducedCount(final SAMRecord read, final int i) { + return getReducedReadQualityTagValue(read)[i]; + } + public final static SAMRecord reducedReadWithReducedQuals(final SAMRecord read) { if ( ! isReducedRead(read) ) throw new IllegalArgumentException("read must be a reduced read"); - try { - SAMRecord newRead = (SAMRecord)read.clone(); - byte reducedQual = (byte)(int)getReducedReadQualityTagValue(read); - byte[] newQuals = new byte[read.getBaseQualities().length]; - Arrays.fill(newQuals, reducedQual); - newRead.setBaseQualities(newQuals); - return newRead; - } catch ( CloneNotSupportedException e ) { - throw new ReviewedStingException("SAMRecord no longer supports clone", e); - } + return read; +// try { +// SAMRecord newRead = (SAMRecord)read.clone(); +// byte reducedQual = (byte)(int)getReducedReadQualityTagValue(read); +// byte[] newQuals = new byte[read.getBaseQualities().length]; +// Arrays.fill(newQuals, reducedQual); +// newRead.setBaseQualities(newQuals); +// return newRead; +// } catch ( CloneNotSupportedException e ) { +// throw new ReviewedStingException("SAMRecord no longer supports clone", e); +// } } // ---------------------------------------------------------------------------------------------------- diff --git a/public/java/test/org/broadinstitute/sting/utils/ReadUtilsUnitTest.java b/public/java/test/org/broadinstitute/sting/utils/ReadUtilsUnitTest.java index e1fdadadc..c14fea24c 100755 --- a/public/java/test/org/broadinstitute/sting/utils/ReadUtilsUnitTest.java +++ b/public/java/test/org/broadinstitute/sting/utils/ReadUtilsUnitTest.java @@ -16,7 +16,7 @@ public class ReadUtilsUnitTest extends BaseTest { SAMRecord read, reducedRead; final static String BASES = "ACTG"; final static String QUALS = "!+5?"; - final private static int REDUCED_READ_QUAL = 20; + final private static byte[] REDUCED_READ_COUNTS = new byte[]{10, 20, 30, 40}; @BeforeTest public void init() { @@ -29,7 +29,7 @@ public class ReadUtilsUnitTest extends BaseTest { reducedRead = ArtificialSAMUtils.createArtificialRead(header, "reducedRead", 0, 1, BASES.length()); reducedRead.setReadBases(BASES.getBytes()); reducedRead.setBaseQualityString(QUALS); - reducedRead.setAttribute(ReadUtils.REDUCED_READ_QUALITY_TAG, REDUCED_READ_QUAL); + reducedRead.setAttribute(ReadUtils.REDUCED_READ_QUALITY_TAG, REDUCED_READ_COUNTS); } private void testReadBasesAndQuals(SAMRecord read, int expectedStart, int expectedStop) { @@ -52,21 +52,10 @@ public class ReadUtilsUnitTest extends BaseTest { Assert.assertEquals(ReadUtils.getReducedReadQualityTagValue(read), null, "No reduced read tag in normal read"); Assert.assertTrue(ReadUtils.isReducedRead(reducedRead), "isReducedRead is true for reduced read"); - Assert.assertEquals((int) ReadUtils.getReducedReadQualityTagValue(reducedRead), REDUCED_READ_QUAL, "Reduced read tag is set to expected value"); - } - - @Test - public void testreducedReadWithReducedQualsWithReducedRead() { - SAMRecord replacedRead = ReadUtils.reducedReadWithReducedQuals(reducedRead); - Assert.assertEquals(replacedRead.getReadBases(), reducedRead.getReadBases()); - Assert.assertEquals(replacedRead.getBaseQualities().length, reducedRead.getBaseQualities().length); - for ( int i = 0; i < replacedRead.getBaseQualities().length; i++) - Assert.assertEquals(replacedRead.getBaseQualities()[i], REDUCED_READ_QUAL); - } - - @Test(expectedExceptions = IllegalArgumentException.class) - public void testreducedReadWithReducedQualsWithNormalRead() { - ReadUtils.reducedReadWithReducedQuals(read); + for ( int i = 0; i < reducedRead.getReadLength(); i++) { + Assert.assertEquals(ReadUtils.getReducedQual(reducedRead, i), read.getBaseQualities()[i], "Reduced read quality not set to the expected value at " + i); + Assert.assertEquals(ReadUtils.getReducedCount(reducedRead, i), REDUCED_READ_COUNTS[i], "Reduced read count not set to the expected value at " + i); + } } @Test @@ -77,8 +66,7 @@ public class ReadUtilsUnitTest extends BaseTest { Assert.assertFalse(readp.isReducedRead()); Assert.assertTrue(reducedreadp.isReducedRead()); - Assert.assertEquals(reducedreadp.getReducedCount(), 0); - Assert.assertEquals(reducedreadp.getReducedQual(), REDUCED_READ_QUAL); - + Assert.assertEquals(reducedreadp.getReducedCount(), REDUCED_READ_COUNTS[0]); + Assert.assertEquals(reducedreadp.getReducedQual(), readp.getQual()); } } From cabacf028d96cd3678d41891e491aedf356473da Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Thu, 29 Sep 2011 18:45:12 -0400 Subject: [PATCH 11/19] Intermediate commit to fix interval skipping may need additional testing. --- .../java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java b/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java index fcb3089cd..3c389fd4c 100755 --- a/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java +++ b/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java @@ -966,4 +966,5 @@ public class ReadUtils { AlignmentStartComparator comp = new AlignmentStartComparator(); return comp.compare(read1, read2); } + } From 05fba6f23ad7c9bb116a03d3243a0e56c1e08d7b Mon Sep 17 00:00:00 2001 From: Mauricio Carneiro Date: Fri, 30 Sep 2011 15:44:30 -0400 Subject: [PATCH 17/19] Clipping ends inside deletion and before insertion fixed. --- .../broadinstitute/sting/utils/sam/ReadUtils.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java b/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java index 3c389fd4c..49900f0da 100755 --- a/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java +++ b/public/java/src/org/broadinstitute/sting/utils/sam/ReadUtils.java @@ -879,9 +879,20 @@ public class ReadUtils { if (endsWithinCigar) fallsInsideDeletion = cigarElement.getOperator() == CigarOperator.DELETION; - // if we end outside the current cigar element, we need to check if the next element is a deletion. + // if we end outside the current cigar element, we need to check if the next element is an insertion or deletion. else { nextCigarElement = cigarElementIterator.next(); + + // if it's an insertion, we need to clip the whole insertion before looking at the next element + if (nextCigarElement.getOperator() == CigarOperator.INSERTION) { + readBases += nextCigarElement.getLength(); + if (!cigarElementIterator.hasNext()) + throw new ReviewedStingException("Reference coordinate corresponds to a non-existent base in the read. This should never happen -- call Mauricio"); + + nextCigarElement = cigarElementIterator.next(); + } + + // if it's a deletion, we will pass the information on to be handled downstream. fallsInsideDeletion = nextCigarElement.getOperator() == CigarOperator.DELETION; } From c7898a9be78130b865cc8d6a8c3e3429ac71eb00 Mon Sep 17 00:00:00 2001 From: Andrey Sivachenko Date: Fri, 30 Sep 2011 16:40:21 -0400 Subject: [PATCH 18/19] inconsequential change in string constants printed into the vcf which noone uses anyway... --- .../gatk/walkers/indels/SomaticIndelDetectorWalker.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/gatk/walkers/indels/SomaticIndelDetectorWalker.java b/public/java/src/org/broadinstitute/sting/gatk/walkers/indels/SomaticIndelDetectorWalker.java index 8bba8eac2..5b10a79c6 100644 --- a/public/java/src/org/broadinstitute/sting/gatk/walkers/indels/SomaticIndelDetectorWalker.java +++ b/public/java/src/org/broadinstitute/sting/gatk/walkers/indels/SomaticIndelDetectorWalker.java @@ -265,7 +265,7 @@ public class SomaticIndelDetectorWalker extends ReadWalker { Set headerInfo = new HashSet(); // first, the basic info - headerInfo.add(new VCFHeaderLine("source", "IndelGenotyperV2")); + headerInfo.add(new VCFHeaderLine("source", "SomaticIndelDetector")); headerInfo.add(new VCFHeaderLine("reference", getToolkit().getArguments().referenceFile.getName())); // FORMAT and INFO fields @@ -283,10 +283,10 @@ public class SomaticIndelDetectorWalker extends ReadWalker { args.addAll(getToolkit().getFilters()); Map commandLineArgs = getToolkit().getApproximateCommandLineArguments(args); for ( Map.Entry commandLineArg : commandLineArgs.entrySet() ) - headerInfo.add(new VCFHeaderLine(String.format("IGv2_%s", commandLineArg.getKey()), commandLineArg.getValue())); + headerInfo.add(new VCFHeaderLine(String.format("SID_%s", commandLineArg.getKey()), commandLineArg.getValue())); // also, the list of input bams for ( String fileName : getToolkit().getArguments().samFiles ) - headerInfo.add(new VCFHeaderLine("IGv2_bam_file_used", fileName)); + headerInfo.add(new VCFHeaderLine("SID_bam_file_used", fileName)); return headerInfo; } From c3eff7451abfcb91366f11158d7eac60fd120199 Mon Sep 17 00:00:00 2001 From: Eric Banks Date: Mon, 3 Oct 2011 14:20:39 -0400 Subject: [PATCH 19/19] Found a small inefficiency while profiling: we were still using String.split instead of ParsingUtils.split to break up array values in the INFO field. There was a noticeable (albeit not big) difference in the change when reading sites only files. --- .../utils/codecs/vcf/AbstractVCFCodec.java | 28 +++++++++++-------- .../sting/utils/codecs/vcf/VCFConstants.java | 1 + 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/AbstractVCFCodec.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/AbstractVCFCodec.java index 43b07476d..c86b91b79 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/AbstractVCFCodec.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/AbstractVCFCodec.java @@ -36,6 +36,7 @@ public abstract class AbstractVCFCodec implements FeatureCodec, NameAwareCodec, // for ParsingUtils.split protected String[] GTValueArray = new String[100]; protected String[] genotypeKeyArray = new String[100]; + protected String[] infoFieldArray = new String[1000]; protected String[] infoValueArray = new String[1000]; // for performance testing purposes @@ -351,23 +352,28 @@ public abstract class AbstractVCFCodec implements FeatureCodec, NameAwareCodec, if ( infoField.indexOf("\t") != -1 || infoField.indexOf(" ") != -1 ) generateException("The VCF specification does not allow for whitespace in the INFO field"); - int infoValueSplitSize = ParsingUtils.split(infoField, infoValueArray, VCFConstants.INFO_FIELD_SEPARATOR_CHAR); - for (int i = 0; i < infoValueSplitSize; i++) { + int infoFieldSplitSize = ParsingUtils.split(infoField, infoFieldArray, VCFConstants.INFO_FIELD_SEPARATOR_CHAR, false); + for (int i = 0; i < infoFieldSplitSize; i++) { String key; Object value; - int eqI = infoValueArray[i].indexOf("="); + int eqI = infoFieldArray[i].indexOf("="); if ( eqI != -1 ) { - key = infoValueArray[i].substring(0, eqI); - String str = infoValueArray[i].substring(eqI+1, infoValueArray[i].length()); + key = infoFieldArray[i].substring(0, eqI); + String str = infoFieldArray[i].substring(eqI+1); - // lets see if the string contains a , separator - if ( str.contains(",") ) - value = Arrays.asList(str.split(",")); - else - value = str; + // split on the INFO field separator + int infoValueSplitSize = ParsingUtils.split(str, infoValueArray, VCFConstants.INFO_FIELD_ARRAY_SEPARATOR_CHAR, false); + if ( infoValueSplitSize == 1 ) { + value = infoValueArray[0]; + } else { + ArrayList valueList = new ArrayList(infoValueSplitSize); + for ( int j = 0; j < infoValueSplitSize; j++ ) + valueList.add(infoValueArray[j]); + value = valueList; + } } else { - key = infoValueArray[i]; + key = infoFieldArray[i]; value = true; } diff --git a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFConstants.java b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFConstants.java index 91cf86c70..8e9d989cc 100755 --- a/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFConstants.java +++ b/public/java/src/org/broadinstitute/sting/utils/codecs/vcf/VCFConstants.java @@ -71,6 +71,7 @@ public final class VCFConstants { public static final char FIELD_SEPARATOR_CHAR = '\t'; public static final String FILTER_CODE_SEPARATOR = ";"; public static final String INFO_FIELD_ARRAY_SEPARATOR = ","; + public static final char INFO_FIELD_ARRAY_SEPARATOR_CHAR = ','; public static final String ID_FIELD_SEPARATOR = ";"; public static final String INFO_FIELD_SEPARATOR = ";"; public static final char INFO_FIELD_SEPARATOR_CHAR = ';';