class BZip2Analyzer extends FileAnalyzer {

    private Genre g;

    @Override
    public Genre getGenre() {
        if (g != null) {
            return g;
        }
        return super.getGenre();
    }

    protected BZip2Analyzer(AnalyzerFactory factory) {
        super(factory);
    }

    /**
     * @return {@code null} as there is no aligned language
     */
    @Override
    public String getCtagsLang() {
        return null;
    }

    /**
     * Gets a version number to be used to tag processed documents so that
     * re-analysis can be re-done later if a stored version number is different
     * from the current implementation.
     * @return 20180111_00
     */
    @Override
    protected int getSpecializedVersionNo() {
        return 20180111_00; // Edit comment above too!
    }

    @Override
    public void analyze(Document doc, StreamSource src, Writer xrefOut)
            throws IOException, InterruptedException {<FILL_FUNCTION_BODY>}

    /**
     * Wrap the raw stream source in one that returns the uncompressed stream.
     */
    private static StreamSource wrap(final StreamSource src) {
        return new StreamSource() {
            @Override
            public InputStream getStream() throws IOException {
                InputStream raw = src.getStream();
                // A BZip2 file starts with "BZ", but CBZip2InputStream
                // expects the magic bytes to be stripped off first.
                if (raw.read() == 'B' && raw.read() == 'Z') {
                    return new BufferedInputStream(new CBZip2InputStream(raw));
                } else {
                    throw new IOException("Not BZIP2 format");
                }
            }
        };
    }
}


        var optionalNewName = Optional.ofNullable(doc.get(QueryBuilder.PATH))
                .filter(path -> path.toUpperCase().endsWith(".BZ2") || path.endsWith(".bz"))
                .map(path -> path.substring(0, path.lastIndexOf('.')));
        if (optionalNewName.isPresent()) {
            StreamSource bzSrc = wrap(src);
            AbstractAnalyzer fa;
            try (InputStream in = bzSrc.getStream()) {
                fa = AnalyzerGuru.getAnalyzer(in, optionalNewName.get());
            }
            if (!(fa instanceof BZip2Analyzer)) {
                this.g = Optional.ofNullable(fa.getGenre())
                        .filter( genre -> genre == Genre.PLAIN || genre == Genre.XREFABLE)
                        .map(genre -> Genre.XREFABLE)
                        .orElse(Genre.DATA);
                fa.analyze(doc, bzSrc, xrefOut);
                if (doc.get(QueryBuilder.T) != null) {
                    doc.removeField(QueryBuilder.T);
                    if (g == Genre.XREFABLE) {
                        doc.add(new Field(QueryBuilder.T, g.typeName(),
                                AnalyzerGuru.string_ft_stored_nanalyzed_norms));
                    }
                }
            }
        }
    
<methods>public void <init>(org.opengrok.indexer.analysis.AnalyzerFactory) ,public void analyze(Document, org.opengrok.indexer.analysis.StreamSource, java.io.Writer) throws java.io.IOException, java.lang.InterruptedException,public java.lang.String getCtagsLang() ,public java.lang.String getFileTypeName() ,public final long getVersionNo() ,public org.opengrok.indexer.analysis.Xrefer writeXref(org.opengrok.indexer.analysis.WriteXrefArgs) throws java.io.IOException<variables>private static final java.util.logging.Logger LOGGER