Open Source Repository

Home /itextpdf/itextpdf-5.1.2 | Repository Home



com/itextpdf/text/pdf/BarcodePDF417.java
/*
 * $Id: BarcodePDF417.java 4784 2011-03-15 08:33:00Z blowagie $
 *
 * This file is part of the iText (R) project.
 * Copyright (c) 1998-2011 1T3XT BVBA
 * Authors: Bruno Lowagie, Paulo Soares, et al.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License version 3
 * as published by the Free Software Foundation with the addition of the
 * following permission added to Section 15 as permitted in Section 7(a):
 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Affero General Public License for more details.
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
 * http://itextpdf.com/terms-of-use/
 *
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License.
 *
 * In accordance with Section 7(b) of the GNU Affero General Public License,
 * a covered work must retain the producer line in every PDF that is created
 * or manipulated using iText.
 *
 * You can be released from the requirements of the license by purchasing
 * a commercial license. Buying such a license is mandatory as soon as you
 * develop commercial activities involving the iText software without
 * disclosing the source code of your own applications.
 * These activities include: offering paid services to customers as an ASP,
 * serving PDFs on the fly in a web application, shipping iText with a closed
 * source product.
 *
 * For more information, please contact iText Software Corp. at this
 * address: [email protected]
 */
package com.itextpdf.text.pdf;

import java.awt.Canvas;
import java.awt.image.MemoryImageSource;
import java.util.ArrayList;

import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Image;
import com.itextpdf.text.error_messages.MessageLocalization;
import com.itextpdf.text.pdf.codec.CCITTG4Encoder;

/** Generates the 2D barcode PDF417. Supports dimensioning auto-sizing, fixed
 * and variable sizes, automatic and manual error levels, raw codeword input,
 * codeword size optimization and bitmap inversion. The output can
 * be a CCITT G4 <CODE>Image</CODE> or a raw bitmap.
 @author Paulo Soares
 */
public class BarcodePDF417 {

    /** Auto-size is made based on <CODE>aspectRatio</CODE> and <CODE>yHeight</CODE>. */
    public static final int PDF417_USE_ASPECT_RATIO = 0;
    /** The size of the barcode will be at least <CODE>codeColumns*codeRows</CODE>. */
    public static final int PDF417_FIXED_RECTANGLE = 1;
    /** The size will be at least <CODE>codeColumns</CODE>
     * with a variable number of <CODE>codeRows</CODE>.
     */
    public static final int PDF417_FIXED_COLUMNS = 2;
    /** The size will be at least <CODE>codeRows</CODE>
     * with a variable number of <CODE>codeColumns</CODE>.
     */
    public static final int PDF417_FIXED_ROWS = 4;
    /** The error level correction is set automatically according
     * to ISO 15438 recommendations.
     */
    public static final int PDF417_AUTO_ERROR_LEVEL = 0;
    /** The error level correction is set by the user. It can be 0 to 8. */
    public static final int PDF417_USE_ERROR_LEVEL = 16;
    /**
     * One single binary segment is used
     */
    public static final int PDF417_FORCE_BINARY = 32;
    /** No <CODE>text</CODE> interpretation is done and the content of <CODE>codewords</CODE>
     * is used directly.
     */
    public static final int PDF417_USE_RAW_CODEWORDS = 64;
    /** Inverts the output bits of the raw bitmap that is normally
     * bit one for black. It has only effect for the raw bitmap.
     */
    public static final int PDF417_INVERT_BITMAP = 128;
    /** Use Macro PDF417 Encoding
     @see #setMacroFileId(String)
     @see #setMacroSegmentId(int)
     @see #setMacroSegmentCount(int)
     */
    public static final int PDF417_USE_MACRO = 256;


    private int macroSegmentCount=0;
    private int macroSegmentId=-1;
    private String macroFileId;
    private int macroIndex;
    protected int bitPtr;
    protected int cwPtr;
    protected SegmentList segmentList;


    /** Creates a new <CODE>BarcodePDF417</CODE> with the default settings. */
    public BarcodePDF417() {
        setDefaultParameters();
    }

    /**
     * Sets the segment id for macro PDF417 encoding
     @param id the id (starting at 0)
     @see #setMacroSegmentCount(int)
     */
    public void setMacroSegmentId(int id) {
        this.macroSegmentId = id;
    }

    /**
     * Sets the segment count for macro PDF417 encoding
     @param cnt the number of macro segments
     @see #setMacroSegmentId(int)
     */
    public void setMacroSegmentCount(int cnt) {
        this.macroSegmentCount = cnt;
    }

    /**
     * Sets the File ID for macro PDF417 encoding
     @param id the file id
     */
    public void setMacroFileId(String id) {
        this.macroFileId = id;
    }

    protected boolean checkSegmentType(Segment segment, char type) {
        if (segment == null)
            return false;
        return segment.type == type;
    }

    protected int getSegmentLength(Segment segment) {
        if (segment == null)
            return 0;
        return segment.end - segment.start;
    }

    /** Set the default settings that correspond to <CODE>PDF417_USE_ASPECT_RATIO</CODE>
     * and <CODE>PDF417_AUTO_ERROR_LEVEL</CODE>.
     */
    public void setDefaultParameters() {
        options = 0;
        outBits = null;
        text = new byte[0];
        yHeight = 3;
        aspectRatio = 0.5f;
    }

    protected void outCodeword17(int codeword) {
        int bytePtr = bitPtr / 8;
        int bit = bitPtr - bytePtr * 8;
        outBits[bytePtr++|= codeword >> + bit;
        outBits[bytePtr++|= codeword >> + bit;
        codeword <<= 8;
        outBits[bytePtr|= codeword >> + bit;
        bitPtr += 17;
    }

    protected void outCodeword18(int codeword) {
        int bytePtr = bitPtr / 8;
        int bit = bitPtr - bytePtr * 8;
        outBits[bytePtr++|= codeword >> 10 + bit;
        outBits[bytePtr++|= codeword >> + bit;
        codeword <<= 8;
        outBits[bytePtr|= codeword >> + bit;
        if (bit == 7)
            outBits[++bytePtr|= 0x80;
        bitPtr += 18;
    }

    protected void outCodeword(int codeword) {
        outCodeword17(codeword);
    }

    protected void outStopPattern() {
        outCodeword18(STOP_PATTERN);
    }

    protected void outStartPattern() {
        outCodeword17(START_PATTERN);
    }

    protected void outPaintCode() {
        int codePtr = 0;
        bitColumns = START_CODE_SIZE * (codeColumns + 3+ STOP_SIZE;
        int lenBits = ((bitColumns - 11* codeRows;
        outBits = new byte[lenBits];
        for (int row = 0; row < codeRows; ++row) {
            bitPtr = ((bitColumns - 11* row;
            int rowMod = row % 3;
            int cluster[] = CLUSTERS[rowMod];
            outStartPattern();
            int edge = 0;
            switch (rowMod) {
            case 0:
                edge = 30 (row / 3(codeRows - 13;
                break;
            case 1:
                edge = 30 (row / 3+ errorLevel * (codeRows - 13;
                break;
            default:
                edge = 30 (row / 3+ codeColumns - 1;
                break;
            }
            outCodeword(cluster[edge]);

            for (int column = 0; column < codeColumns; ++column) {
                outCodeword(cluster[codewords[codePtr++]]);
            }

            switch (rowMod) {
            case 0:
                edge = 30 (row / 3+ codeColumns - 1;
                break;
            case 1:
                edge = 30 (row / 3(codeRows - 13;
                break;
            default:
                edge = 30 (row / 3+ errorLevel * (codeRows - 13;
                break;
            }
            outCodeword(cluster[edge]);
            outStopPattern();
        }
        if ((options & PDF417_INVERT_BITMAP!= 0) {
            for (int k = 0; k < outBits.length; ++k)
                outBits[k^= 0xff;
        }
    }

    protected void calculateErrorCorrection(int dest) {
        if (errorLevel < || errorLevel > 8)
            errorLevel = 0;
        int A[] = ERROR_LEVEL[errorLevel];
        int Alength = << errorLevel;
        for (int k = 0; k < Alength; ++k)
            codewords[dest + k0;
        int lastE = Alength - 1;
        for (int k = 0; k < lenCodewords; ++k) {
            int t1 = codewords[k+ codewords[dest];
            for (int e = 0; e <= lastE; ++e) {
                int t2 = t1 * A[lastE - e% MOD;
                int t3 = MOD - t2;
                codewords[dest + e((e == lastE ? : codewords[dest + e + 1]) + t3% MOD;
            }
        }
        for (int k = 0; k < Alength; ++k)
            codewords[dest + k(MOD - codewords[dest + k]) % MOD;
    }

    private static int getTextTypeAndValue(byte[] input, int maxLength, int idx) {
        if (idx >= maxLength)
            return 0;
        char c = (char)(input[idx0xff);
        if (c >= 'A' && c <= 'Z')
            return ALPHA + c - 'A';
        if (c >= 'a' && c <= 'z')
            return LOWER + c - 'a';
        if (c == ' ')
            return ALPHA + LOWER + MIXED + SPACE;
        int ms = MIXED_SET.indexOf(c);
        int ps = PUNCTUATION_SET.indexOf(c);
        if (ms < && ps < 0)
            return ISBYTE + c;
        if (ms == ps)
            return MIXED + PUNCTUATION + ms;
        if (ms >= 0)
            return MIXED + ms;
        return PUNCTUATION + ps;
    }

    protected int getTextTypeAndValue(int maxLength, int idx) {
        return getTextTypeAndValue(text, maxLength,idx);
    }

    private void textCompaction(byte[] input, int start, int length) {
        int dest[] new int[ABSOLUTE_MAX_TEXT_SIZE * 2];
        int mode = ALPHA;
        int ptr = 0;
        int fullBytes = 0;
        int v = 0;
        int k;
        int size;
        length += start;
        for (k = start; k < length; ++k) {
            v = getTextTypeAndValue(input, length, k);
            if ((v & mode!= 0) {
                dest[ptr++= v & 0xff;
                continue;
            }
            if ((v & ISBYTE!= 0) {
                if ((ptr & 1!= 0) {
                    //add a padding word
                    dest[ptr++= PAL;
                    mode = (mode & PUNCTUATION!= ? ALPHA : mode;
                }
                dest[ptr++= BYTESHIFT;
                dest[ptr++= v & 0xff;
                fullBytes += 2;
                continue;
            }
            switch (mode) {
            case ALPHA:
                if ((v & LOWER!= 0) {
                    dest[ptr++= LL;
                    dest[ptr++= v & 0xff;
                    mode = LOWER;
                }
                else if ((v & MIXED!= 0) {
                    dest[ptr++= ML;
                    dest[ptr++= v & 0xff;
                    mode = MIXED;
                }
                else if ((getTextTypeAndValue(input, length, k + 1& getTextTypeAndValue(input, length, k + 2& PUNCTUATION!= 0) {
                    dest[ptr++= ML;
                    dest[ptr++= PL;
                    dest[ptr++= v & 0xff;
                    mode = PUNCTUATION;
                }
                else {
                    dest[ptr++= PS;
                    dest[ptr++= v & 0xff;
                }
                break;
            case LOWER:
                if ((v & ALPHA!= 0) {
                    if ((getTextTypeAndValue(input, length, k + 1& getTextTypeAndValue(input, length, k + 2& ALPHA!= 0) {
                        dest[ptr++= ML;
                        dest[ptr++= AL;
                        mode = ALPHA;
                    }
                    else {
                        dest[ptr++= AS;
                    }
                    dest[ptr++= v & 0xff;
                }
                else if ((v & MIXED!= 0) {
                    dest[ptr++= ML;
                    dest[ptr++= v & 0xff;
                    mode = MIXED;
                }
                else if ((getTextTypeAndValue(input, length, k + 1& getTextTypeAndValue(input, length, k + 2& PUNCTUATION!= 0) {
                    dest[ptr++= ML;
                    dest[ptr++= PL;
                    dest[ptr++= v & 0xff;
                    mode = PUNCTUATION;
                }
                else {
                    dest[ptr++= PS;
                    dest[ptr++= v & 0xff;
                }
                break;
            case MIXED:
                if ((v & LOWER!= 0) {
                    dest[ptr++= LL;
                    dest[ptr++= v & 0xff;
                    mode = LOWER;
                }
                else if ((v & ALPHA!= 0) {
                    dest[ptr++= AL;
                    dest[ptr++= v & 0xff;
                    mode = ALPHA;
                }
                else if ((getTextTypeAndValue(input, length, k + 1& getTextTypeAndValue(input, length, k + 2& PUNCTUATION!= 0) {
                    dest[ptr++= PL;
                    dest[ptr++= v & 0xff;
                    mode = PUNCTUATION;
                }
                else {
                    dest[ptr++= PS;
                    dest[ptr++= v & 0xff;
                }
                break;
            case PUNCTUATION:
                dest[ptr++= PAL;
                mode = ALPHA;
                --k;
                break;
            }
        }
        if ((ptr & 1!= 0)
            dest[ptr++= PS;
        size = (ptr + fullBytes2;
        if (size + cwPtr > MAX_DATA_CODEWORDS) {
            throw new IndexOutOfBoundsException(MessageLocalization.getComposedMessage("the.text.is.too.big"));
        }
        length = ptr;
        ptr = 0;
        while (ptr < length) {
            v = dest[ptr++];
            if (v >= 30) {
                codewords[cwPtr++= v;
                codewords[cwPtr++= dest[ptr++];
            }
            else
                codewords[cwPtr++= v * 30 + dest[ptr++];
        }
    }
    protected void textCompaction(int start, int length) {
        textCompaction(text, start, length);
    }

    protected void basicNumberCompaction(int start, int length) {
        basicNumberCompaction(text, start, length);
    }

    private void basicNumberCompaction(byte[] input, int start, int length) {
        int ret = cwPtr;
        int retLast = length / 3;
        int ni, k;
        cwPtr += retLast + 1;
        for (k = 0; k <= retLast; ++k)
            codewords[ret + k0;
        codewords[ret + retLast1;
        length += start;
        for (ni = start; ni < length; ++ni) {
            // multiply by 10
            for (k = retLast; k >= 0; --k)
                codewords[ret + k*= 10;
            // add the digit
            codewords[ret + retLast+= input[ni'0';
            // propagate carry
            for (k = retLast; k > 0; --k) {
                codewords[ret + k - 1+= codewords[ret + k900;
                codewords[ret + k%= 900;
            }
        }
    }

    private void numberCompaction(byte[] input, int start, int length) {
        int full = length / 44 15;
        int size = length % 44;
        int k;
        if (size == 0)
            size = full;
        else
            size = full + size / 1;
        if (size + cwPtr > MAX_DATA_CODEWORDS) {
            throw new IndexOutOfBoundsException(MessageLocalization.getComposedMessage("the.text.is.too.big"));
        }
        length += start;
        for (k = start; k < length; k += 44) {
            size = length - k < 44 ? length - k : 44;
            basicNumberCompaction(input, k, size);
        }
        }

    protected void numberCompaction(int start, int length) {
        numberCompaction(text, start, length);
    }

    protected void byteCompaction6(int start) {
        int length = 6;
        int ret = cwPtr;
        int retLast = 4;
        int ni, k;
        cwPtr += retLast + 1;
        for (k = 0; k <= retLast ; ++k)
            codewords[ret + k0;
        length += start;
        for (ni = start; ni < length; ++ni) {
            // multiply by 256
            for (k = retLast; k >= 0; --k)
                codewords[ret + k*= 256;
            // add the digit
            codewords[ret + retLast+= text[ni0xff;
            // propagate carry
            for (k = retLast; k > 0; --k) {
                codewords[ret + k - 1+= codewords[ret + k900;
                codewords[ret + k%= 900;
            }
        }
    }

    void byteCompaction(int start, int length) {
        int k, j;
        int size = length / + length % 6;
        if (size + cwPtr > MAX_DATA_CODEWORDS) {
            throw new IndexOutOfBoundsException(MessageLocalization.getComposedMessage("the.text.is.too.big"));
        }
        length += start;
        for (k = start; k < length; k += 6) {
            size = length - k < 44 ? length - k : 6;
            if (size < 6) {
                for (j = 0; j < size; ++j)
                    codewords[cwPtr++= text[k + j0xff;
            }
            else {
                byteCompaction6(k);
            }
        }
    }

    void breakString() {
        int textLength = text.length;
        int lastP = 0;
        int startN = 0;
        int nd = 0;
        char c = 0;
        int k, j;
        boolean lastTxt, txt;
        Segment v;
        Segment vp;
        Segment vn;

        if ((options & PDF417_FORCE_BINARY!= 0) {
            segmentList.add('B'0, textLength);
            return;
        }
        for (k = 0; k < textLength; ++k) {
            c = (char)(text[k0xff);
            if (c >= '0' && c <= '9') {
                if (nd == 0)
                    startN = k;
                ++nd;
                continue;
            }
            if (nd >= 13) {
                if (lastP != startN) {
                    c = (char)(text[lastP0xff);
                    lastTxt = c >= ' ' && c < 127 || c == '\r' || c == '\n' || c == '\t';
                    for (j = lastP; j < startN; ++j) {
                        c = (char)(text[j0xff);
                        txt = c >= ' ' && c < 127 || c == '\r' || c == '\n' || c == '\t';
                        if (txt != lastTxt) {
                            segmentList.add(lastTxt ? 'T' 'B', lastP, j);
                            lastP = j;
                            lastTxt = txt;
                        }
                    }
                    segmentList.add(lastTxt ? 'T' 'B', lastP, startN);
                }
                segmentList.add('N', startN, k);
                lastP = k;
            }
            nd = 0;
        }
        if (nd < 13)
            startN = textLength;
        if (lastP != startN) {
            c = (char)(text[lastP0xff);
            lastTxt = c >= ' ' && c < 127 || c == '\r' || c == '\n' || c == '\t';
            for (j = lastP; j < startN; ++j) {
                c = (char)(text[j0xff);
                txt = c >= ' ' && c < 127 || c == '\r' || c == '\n' || c == '\t';
                if (txt != lastTxt) {
                    segmentList.add(lastTxt ? 'T' 'B', lastP, j);
                    lastP = j;
                    lastTxt = txt;
                }
            }
            segmentList.add(lastTxt ? 'T' 'B', lastP, startN);
        }
        if (nd >= 13)
            segmentList.add('N', startN, textLength);
        //optimize
        //merge short binary
        for (k = 0; k < segmentList.size(); ++k) {
            v = segmentList.get(k);
            vp = segmentList.get(k - 1);
            vn = segmentList.get(k + 1);
            if (checkSegmentType(v, 'B'&& getSegmentLength(v== 1) {
                if (checkSegmentType(vp, 'T'&& checkSegmentType(vn, 'T')
                    && getSegmentLength(vp+ getSegmentLength(vn>= 3) {
                    vp.end = vn.end;
                    segmentList.remove(k);
                    segmentList.remove(k);
                    k = -1;
                    continue;
                }
            }
        }
        //merge text sections
        for (k = 0; k < segmentList.size(); ++k) {
            v = segmentList.get(k);
            vp = segmentList.get(k - 1);
            vn = segmentList.get(k + 1);
            if (checkSegmentType(v, 'T'&& getSegmentLength(v>= 5) {
                boolean redo = false;
                if (checkSegmentType(vp, 'B'&& getSegmentLength(vp== || checkSegmentType(vp, 'T')) {
                    redo = true;
                    v.start = vp.start;
                    segmentList.remove(k - 1);
                    --k;
                }
                if (checkSegmentType(vn, 'B'&& getSegmentLength(vn== || checkSegmentType(vn, 'T')) {
                    redo = true;
                    v.end = vn.end;
                    segmentList.remove(k + 1);
                }
                if (redo) {
                    k = -1;
                    continue;
                }
            }
        }
        //merge binary sections
        for (k = 0; k < segmentList.size(); ++k) {
            v = segmentList.get(k);
            vp = segmentList.get(k - 1);
            vn = segmentList.get(k + 1);
            if (checkSegmentType(v, 'B')) {
                boolean redo = false;
                if (checkSegmentType(vp, 'T'&& getSegmentLength(vp|| checkSegmentType(vp, 'B')) {
                    redo = true;
                    v.start = vp.start;
                    segmentList.remove(k - 1);
                    --k;
                }
                if (checkSegmentType(vn, 'T'&& getSegmentLength(vn|| checkSegmentType(vn, 'B')) {
                    redo = true;
                    v.end = vn.end;
                    segmentList.remove(k + 1);
                }
                if (redo) {
                    k = -1;
                    continue;
                }
            }
        }
        // check if all numbers
        if (segmentList.size() == && (v = segmentList.get(0)).type == 'T' && getSegmentLength(v>= 8) {
            for (k = v.start; k < v.end; ++k) {
                c = (char)(text[k0xff);
                if (c < '0' || c > '9')
                    break;
            }
            if (k == v.end)
                v.type = 'N';
        }
    }

    protected void assemble() {
        int k;
        if (segmentList.size() == 0)
            return;
        cwPtr = 1;
        for (k = 0; k < segmentList.size(); ++k) {
            Segment v = segmentList.get(k);
            switch (v.type) {
            case 'T':
                if (k != 0)
                    codewords[cwPtr++= TEXT_MODE;
                textCompaction(v.start, getSegmentLength(v));
                break;
            case 'N':
                codewords[cwPtr++= NUMERIC_MODE;
                numberCompaction(v.start, getSegmentLength(v));
                break;
            case 'B':
                codewords[cwPtr++= getSegmentLength(v!= ? BYTE_MODE : BYTE_MODE_6;
                byteCompaction(v.start, getSegmentLength(v));
                break;
            }
        }

        if ((options & PDF417_USE_MACRO!= 0) {
            macroCodes();
        }

    }

    private void macroCodes() {
        if (macroSegmentId < 0) {
            throw new IllegalStateException(MessageLocalization.getComposedMessage("macrosegmentid.must.be.gt.eq.0"));
        }
        if (macroSegmentId >= macroSegmentCount) {
            throw new IllegalStateException(MessageLocalization.getComposedMessage("macrosegmentid.must.be.lt.macrosemgentcount"));
        }
        if (macroSegmentCount < 1) {
            throw new IllegalStateException(MessageLocalization.getComposedMessage("macrosemgentcount.must.be.gt.0"));
        }

        macroIndex = cwPtr;
        codewords[cwPtr++= MACRO_SEGMENT_ID;
        append(macroSegmentId, 5);

        if (macroFileId != null) {
            append(macroFileId);
        }

        if (macroSegmentId >= macroSegmentCount-1) {
            codewords[cwPtr++= MACRO_LAST_SEGMENT;
        }

    }

    private void append(int in, int len) {
        StringBuffer sb = new StringBuffer(len+1);
        sb.append(Integer.toString(in));
        for(int i = sb.length(); i < len; i++) {
            sb.insert(0"0");
        }

        byte[] bytes = PdfEncodings.convertToBytes(sb.toString()"cp437");
        numberCompaction(bytes, 0, bytes.length);
    }

    private void append(String s) {
        byte[] bytes = PdfEncodings.convertToBytes(s, "cp437");
        textCompaction(bytes, 0, bytes.length);
    }


    protected static int maxPossibleErrorLevel(int remain) {
        int level = 8;
        int size = 512;
        while (level > 0) {
            if (remain >= size)
                return level;
            --level;
            size >>= 1;
        }
        return 0;
    }

    protected void dumpList() {
        if (segmentList.size() == 0)
            return;
        for (int k = 0; k < segmentList.size(); ++k) {
            Segment v = segmentList.get(k);
            int len = getSegmentLength(v);
            char c[] new char[len];
            for (int j = 0; j < len; ++j) {
                c[j(char)(text[v.start + j0xff);
                if (c[j== '\r')
                    c[j'\n';
            }
            StringBuffer sb = new StringBuffer();
            sb.append(v.type);
            sb.append(c);
            System.out.println(sb.toString());
        }
    }

    protected int getMaxSquare() {
        if (codeColumns > 21) {
            codeColumns = 29;
            codeRows = 32;
        }
        else {
            codeColumns = 16;
            codeRows = 58;
        }
        return MAX_DATA_CODEWORDS + 2;
    }

    /** Paints the barcode. If no exception was thrown a valid barcode is available. */
    public void paintCode() {
        int maxErr, lenErr, tot, pad;
        if ((options & PDF417_USE_RAW_CODEWORDS!= 0) {
            if (lenCodewords > MAX_DATA_CODEWORDS || lenCodewords < || lenCodewords != codewords[0]) {
                throw new IllegalArgumentException(MessageLocalization.getComposedMessage("invalid.codeword.size"));
            }
        }
        else {
            if (text == null)
                throw new NullPointerException(MessageLocalization.getComposedMessage("text.cannot.be.null"));
            if (text.length > ABSOLUTE_MAX_TEXT_SIZE) {
                throw new IndexOutOfBoundsException(MessageLocalization.getComposedMessage("the.text.is.too.big"));
            }
            segmentList = new SegmentList();
            breakString();
            //dumpList();
            assemble();
            segmentList = null;
            codewords[0= lenCodewords = cwPtr;
        }
        maxErr = maxPossibleErrorLevel(MAX_DATA_CODEWORDS + - lenCodewords);
        if ((options & PDF417_USE_ERROR_LEVEL== 0) {
            if (lenCodewords < 41)
                errorLevel = 2;
            else if (lenCodewords < 161)
                errorLevel = 3;
            else if (lenCodewords < 321)
                errorLevel = 4;
            else
                errorLevel = 5;
        }
        if (errorLevel < 0)
            errorLevel = 0;
        else if (errorLevel > maxErr)
            errorLevel = maxErr;
        if (codeColumns < 1)
            codeColumns = 1;
        else if (codeColumns > 30)
            codeColumns = 30;
        if (codeRows < 3)
            codeRows = 3;
        else if (codeRows > 90)
            codeRows = 90;
        lenErr = << errorLevel;
        boolean fixedColumn = (options & PDF417_FIXED_ROWS== 0;
        boolean skipRowColAdjust = false;
        tot = lenCodewords + lenErr;
        if ((options & PDF417_FIXED_RECTANGLE!= 0) {
            tot = codeColumns * codeRows;
            if (tot > MAX_DATA_CODEWORDS + 2) {
                tot = getMaxSquare();
            }
            if (tot < lenCodewords + lenErr)
                tot = lenCodewords + lenErr;
            else
                skipRowColAdjust = true;
        }
        else if ((options & (PDF417_FIXED_COLUMNS | PDF417_FIXED_ROWS)) == 0) {
            double c, b;
            fixedColumn = true;
            if (aspectRatio < 0.001)
                aspectRatio = 0.001f;
            else if (aspectRatio > 1000)
                aspectRatio = 1000;
            b = 73 * aspectRatio - 4;
            c = (-b + Math.sqrt(b * b + 17 * aspectRatio * (lenCodewords + lenErr* yHeight)) (17 * aspectRatio);
            codeColumns = (int)(c + 0.5);
            if (codeColumns < 1)
                codeColumns = 1;
            else if (codeColumns > 30)
                codeColumns = 30;
        }
        if (!skipRowColAdjust) {
            if (fixedColumn) {
                codeRows = (tot - 1/ codeColumns + 1;
                if (codeRows < 3)
                    codeRows = 3;
                else if (codeRows > 90) {
                    codeRows = 90;
                    codeColumns = (tot - 190 1;
                }
            }
            else {
                codeColumns = (tot - 1/ codeRows + 1;
                if (codeColumns > 30) {
                    codeColumns = 30;
                    codeRows = (tot - 130 1;
                }
            }
            tot = codeRows * codeColumns;
        }
        if (tot > MAX_DATA_CODEWORDS + 2) {
            tot = getMaxSquare();
        }
        errorLevel = maxPossibleErrorLevel(tot - lenCodewords);
        lenErr = << errorLevel;
        pad = tot - lenErr - lenCodewords;
        if ((options & PDF417_USE_MACRO!= 0) {
            // the padding comes before the control block
            System.arraycopy(codewords, macroIndex, codewords, macroIndex + pad, pad);
            cwPtr = lenCodewords + pad;
            while (pad-- != 0)
                codewords[macroIndex++= TEXT_MODE;
        }
        else {
            cwPtr = lenCodewords;
            while (pad-- != 0)
                codewords[cwPtr++= TEXT_MODE;
        }
        codewords[0= lenCodewords = cwPtr;
        calculateErrorCorrection(lenCodewords);
        lenCodewords = tot;
        outPaintCode();
    }

    /** Gets an <CODE>Image</CODE> with the barcode. The image will have to be
     * scaled in the Y direction by <CODE>yHeight</CODE>for the barcode
     * to have the right printing aspect.
     @return the barcode <CODE>Image</CODE>
     @throws BadElementException on error
     */
    public Image getImage() throws BadElementException {
        paintCode();
        byte g4[] = CCITTG4Encoder.compress(outBits, bitColumns, codeRows);
        return Image.getInstance(bitColumns, codeRows, false, Image.CCITTG4, (options & PDF417_INVERT_BITMAP== : Image.CCITT_BLACKIS1, g4, null);
    }

    /** Creates a <CODE>java.awt.Image</CODE>.
     @param foreground the color of the bars
     @param background the color of the background
     @return the image
     */
    public java.awt.Image createAwtImage(java.awt.Color foreground, java.awt.Color background) {
        int f = foreground.getRGB();
        int g = background.getRGB();
        Canvas canvas = new Canvas();

        paintCode();
        int h = (int)yHeight;
        int pix[] new int[bitColumns * codeRows * h];
        int stride = (bitColumns + 78;
        int ptr = 0;
        for (int k = 0; k < codeRows; ++k) {
            int p = k * stride;
            for (int j = 0; j < bitColumns; ++j) {
                int b = outBits[p + j / 80xff;
                b <<= j % 8;
                pix[ptr++(b & 0x80== ? g : f;
            }
            for (int j = 1; j < h; ++j) {
                System.arraycopy(pix, ptr - bitColumns, pix, ptr + bitColumns * (j - 1), bitColumns);
            }
            ptr += bitColumns * (h - 1);
        }

        java.awt.Image img = canvas.createImage(new MemoryImageSource(bitColumns, codeRows * h, pix, 0, bitColumns));
        return img;
    }

    /** Gets the raw image bits of the barcode. The image will have to
     * be scaled in the Y direction by <CODE>yHeight</CODE>.
     @return The raw barcode image
     */
    public byte[] getOutBits() {
        return this.outBits;
    }

    /** Gets the number of X pixels of <CODE>outBits</CODE>.
     @return the number of X pixels of <CODE>outBits</CODE>
     */
    public int getBitColumns() {
        return this.bitColumns;
    }

    /** Gets the number of Y pixels of <CODE>outBits</CODE>.
     * It is also the number of rows in the barcode.
     @return the number of Y pixels of <CODE>outBits</CODE>
     */
    public int getCodeRows() {
        return this.codeRows;
    }

    /** Sets the number of barcode rows. This number may be changed
     * to keep the barcode valid.
     @param codeRows the number of barcode rows
     */
    public void setCodeRows(int codeRows) {
        this.codeRows = codeRows;
    }

    /** Gets the number of barcode data columns.
     @return he number of barcode data columns
     */
    public int getCodeColumns() {
        return this.codeColumns;
    }

    /** Sets the number of barcode data columns.
     * This number may be changed to keep the barcode valid.
     @param codeColumns the number of barcode data columns
     */
    public void setCodeColumns(int codeColumns) {
        this.codeColumns = codeColumns;
    }

    /** Gets the codeword array. This array is always 928 elements long.
     * It can be written to if the option <CODE>PDF417_USE_RAW_CODEWORDS</CODE>
     * is set.
     @return the codeword array
     */
    public int[] getCodewords() {
        return this.codewords;
    }

    /** Gets the length of the codewords.
     @return the length of the codewords
     */
    public int getLenCodewords() {
        return this.lenCodewords;
    }

    /** Sets the length of the codewords.
     @param lenCodewords the length of the codewords
     */
    public void setLenCodewords(int lenCodewords) {
        this.lenCodewords = lenCodewords;
    }

    /** Gets the error level correction used for the barcode. It may different
     * from the previously set value.
     @return the error level correction used for the barcode
     */
    public int getErrorLevel() {
        return this.errorLevel;
    }

    /** Sets the error level correction for the barcode.
     @param errorLevel the error level correction for the barcode
     */
    public void setErrorLevel(int errorLevel) {
        this.errorLevel = errorLevel;
    }

    /** Gets the bytes that form the barcode. This bytes should
     * be interpreted in the codepage Cp437.
     @return the bytes that form the barcode
     */
    public byte[] getText() {
        return this.text;
    }

    /** Sets the bytes that form the barcode. This bytes should
     * be interpreted in the codepage Cp437.
     @param text the bytes that form the barcode
     */
    public void setText(byte[] text) {
        this.text = text;
    }

    /** Sets the text that will form the barcode. This text is converted
     * to bytes using the encoding Cp437.
     @param s the text that will form the barcode
     */
    public void setText(String s) {
        this.text = PdfEncodings.convertToBytes(s, "cp437");
    }

    /** Gets the options to generate the barcode.
     @return the options to generate the barcode
     */
    public int getOptions() {
        return this.options;
    }

    /** Sets the options to generate the barcode. This can be all
     * the <CODE>PDF417_*</CODE> constants.
     @param options the options to generate the barcode
     */
    public void setOptions(int options) {
        this.options = options;
    }

    /** Gets the barcode aspect ratio.
     @return the barcode aspect ratio
     */
    public float getAspectRatio() {
        return this.aspectRatio;
    }

    /** Sets the barcode aspect ratio. A ratio or 0.5 will make the
     * barcode width twice as large as the height.
     @param aspectRatio the barcode aspect ratio
     */
    public void setAspectRatio(float aspectRatio) {
        this.aspectRatio = aspectRatio;
    }

    /** Gets the Y pixel height relative to X.
     @return the Y pixel height relative to X
     */
    public float getYHeight() {
        return this.yHeight;
    }

    /** Sets the Y pixel height relative to X. It is usually 3.
     @param yHeight the Y pixel height relative to X
     */
    public void setYHeight(float yHeight) {
        this.yHeight = yHeight;
    }

    protected static final int START_PATTERN = 0x1fea8;
    protected static final int STOP_PATTERN = 0x3fa29;
    protected static final int START_CODE_SIZE = 17;
    protected static final int STOP_SIZE = 18;
    protected static final int MOD = 929;
    protected static final int ALPHA = 0x10000;
    protected static final int LOWER = 0x20000;
    protected static final int MIXED = 0x40000;
    protected static final int PUNCTUATION = 0x80000;
    protected static final int ISBYTE = 0x100000;
    protected static final int BYTESHIFT = 913;
    protected static final int PL = 25;
    protected static final int LL = 27;
    protected static final int AS = 27;
    protected static final int ML = 28;
    protected static final int AL = 28;
    protected static final int PS = 29;
    protected static final int PAL = 29;
    protected static final int SPACE = 26;
    protected static final int TEXT_MODE = 900;
    protected static final int BYTE_MODE_6 = 924;
    protected static final int BYTE_MODE = 901;
    protected static final int NUMERIC_MODE = 902;
    protected static final int ABSOLUTE_MAX_TEXT_SIZE = 5420;
    protected static final int MAX_DATA_CODEWORDS = 926;
    protected static final int MACRO_SEGMENT_ID=928;
    protected static final int MACRO_LAST_SEGMENT=922;

    private static final String MIXED_SET = "0123456789&\r\t,:#-.$/+%*=^";
    private static final String PUNCTUATION_SET = ";<>@[\\]_`~!\r\t,:\n-.$/\"|*()?{}'";

    private static final int CLUSTERS[][] =
    {{
         0x1d5c00x1eaf00x1f57c0x1d4e00x1ea780x1f53e0x1a8c00x1d470,
         0x1a8600x150400x1a8300x150200x1adc00x1d6f00x1eb7c0x1ace0,
         0x1d6780x1eb3e0x158c00x1ac700x158600x15dc00x1aef00x1d77c,
         0x15ce00x1ae780x1d73e0x15c700x1ae3c0x15ef00x1af7c0x15e78,
         0x1af3e0x15f7c0x1f5fa0x1d2e00x1e9780x1f4be0x1a4c00x1d270,
         0x1e93c0x1a4600x1d2380x148400x1a4300x1d21c0x148200x1a418,
         0x148100x1a6e00x1d3780x1e9be0x14cc00x1a6700x1d33c0x14c60,
         0x1a6380x1d31e0x14c300x1a61c0x14ee00x1a7780x1d3be0x14e70,
         0x1a73c0x14e380x1a71e0x14f780x1a7be0x14f3c0x14f1e0x1a2c0,
         0x1d1700x1e8bc0x1a2600x1d1380x1e89e0x144400x1a2300x1d11c,
         0x144200x1a2180x144100x144080x146c00x1a3700x1d1bc0x14660,
         0x1a3380x1d19e0x146300x1a31c0x146180x1460c0x147700x1a3bc,
         0x147380x1a39e0x1471c0x147bc0x1a1600x1d0b80x1e85e0x14240,
         0x1a1300x1d09c0x142200x1a1180x1d08e0x142100x1a10c0x14208,
         0x1a1060x143600x1a1b80x1d0de0x143300x1a19c0x143180x1a18e,
         0x1430c0x143060x1a1de0x1438e0x141400x1a0b00x1d05c0x14120,
         0x1a0980x1d04e0x141100x1a08c0x141080x1a0860x141040x141b0,
         0x141980x1418c0x140a00x1d02e0x1a04c0x1a0460x140820x1cae0,
         0x1e5780x1f2be0x194c00x1ca700x1e53c0x194600x1ca380x1e51e,
         0x128400x194300x128200x196e00x1cb780x1e5be0x12cc00x19670,
         0x1cb3c0x12c600x196380x12c300x12c180x12ee00x197780x1cbbe,
         0x12e700x1973c0x12e380x12e1c0x12f780x197be0x12f3c0x12fbe,
         0x1dac00x1ed700x1f6bc0x1da600x1ed380x1f69e0x1b4400x1da30,
         0x1ed1c0x1b4200x1da180x1ed0e0x1b4100x1da0c0x192c00x1c970,
         0x1e4bc0x1b6c00x192600x1c9380x1e49e0x1b6600x1db380x1ed9e,
         0x16c400x124200x192180x1c90e0x16c200x1b6180x16c100x126c0,
         0x193700x1c9bc0x16ec00x126600x193380x1c99e0x16e600x1b738,
         0x1db9e0x16e300x126180x16e180x127700x193bc0x16f700x12738,
         0x1939e0x16f380x1b79e0x16f1c0x127bc0x16fbc0x1279e0x16f9e,
         0x1d9600x1ecb80x1f65e0x1b2400x1d9300x1ec9c0x1b2200x1d918,
         0x1ec8e0x1b2100x1d90c0x1b2080x1b2040x191600x1c8b80x1e45e,
         0x1b3600x191300x1c89c0x166400x122200x1d99c0x1c88e0x16620,
         0x122100x1910c0x166100x1b30c0x191060x122040x123600x191b8,
         0x1c8de0x167600x123300x1919c0x167300x1b39c0x1918e0x16718,
         0x1230c0x123060x123b80x191de0x167b80x1239c0x1679c0x1238e,
         0x1678e0x167de0x1b1400x1d8b00x1ec5c0x1b1200x1d8980x1ec4e,
         0x1b1100x1d88c0x1b1080x1d8860x1b1040x1b1020x121400x190b0,
         0x1c85c0x163400x121200x190980x1c84e0x163200x1b1980x1d8ce,
         0x163100x121080x190860x163080x1b1860x163040x121b00x190dc,
         0x163b00x121980x190ce0x163980x1b1ce0x1638c0x121860x16386,
         0x163dc0x163ce0x1b0a00x1d8580x1ec2e0x1b0900x1d84c0x1b088,
         0x1d8460x1b0840x1b0820x120a00x190580x1c82e0x161a00x12090,
         0x1904c0x161900x1b0cc0x190460x161880x120840x161840x12082,
         0x120d80x161d80x161cc0x161c60x1d82c0x1d8260x1b0420x1902c,
         0x120480x160c80x160c40x160c20x18ac00x1c5700x1e2bc0x18a60,
         0x1c5380x114400x18a300x1c51c0x114200x18a180x114100x11408,
         0x116c00x18b700x1c5bc0x116600x18b380x1c59e0x116300x18b1c,
         0x116180x1160c0x117700x18bbc0x117380x18b9e0x1171c0x117bc,
         0x1179e0x1cd600x1e6b80x1f35e0x19a400x1cd300x1e69c0x19a20,
         0x1cd180x1e68e0x19a100x1cd0c0x19a080x1cd060x189600x1c4b8,
         0x1e25e0x19b600x189300x1c49c0x136400x112200x1cd9c0x1c48e,
         0x136200x19b180x1890c0x136100x112080x136080x113600x189b8,
         0x1c4de0x137600x113300x1cdde0x137300x19b9c0x1898e0x13718,
         0x1130c0x1370c0x113b80x189de0x137b80x1139c0x1379c0x1138e,
         0x113de0x137de0x1dd400x1eeb00x1f75c0x1dd200x1ee980x1f74e,
         0x1dd100x1ee8c0x1dd080x1ee860x1dd040x199400x1ccb00x1e65c,
         0x1bb400x199200x1eedc0x1e64e0x1bb200x1dd980x1eece0x1bb10,
         0x199080x1cc860x1bb080x1dd860x199020x111400x188b00x1c45c,
         0x133400x111200x188980x1c44e0x177400x133200x199980x1ccce,
         0x177200x1bb980x1ddce0x188860x177100x133080x199860x17708,
         0x111020x111b00x188dc0x133b00x111980x188ce0x177b00x13398,
         0x199ce0x177980x1bbce0x111860x133860x111dc0x133dc0x111ce,
         0x177dc0x133ce0x1dca00x1ee580x1f72e0x1dc900x1ee4c0x1dc88,
         0x1ee460x1dc840x1dc820x198a00x1cc580x1e62e0x1b9a00x19890,
         0x1ee6e0x1b9900x1dccc0x1cc460x1b9880x198840x1b9840x19882,
         0x1b9820x110a00x188580x1c42e0x131a00x110900x1884c0x173a0,
         0x131900x198cc0x188460x173900x1b9cc0x110840x173880x13184,
         0x110820x131820x110d80x1886e0x131d80x110cc0x173d80x131cc,
         0x110c60x173cc0x131c60x110ee0x173ee0x1dc500x1ee2c0x1dc48,
         0x1ee260x1dc440x1dc420x198500x1cc2c0x1b8d00x198480x1cc26,
         0x1b8c80x1dc660x1b8c40x198420x1b8c20x110500x1882c0x130d0,
         0x110480x188260x171d00x130c80x198660x171c80x1b8e60x11042,
         0x171c40x130c20x171c20x130ec0x171ec0x171e60x1ee160x1dc22,
         0x1cc160x198240x198220x110280x130680x170e80x110220x13062,
         0x185600x10a400x185300x10a200x185180x1c28e0x10a100x1850c,
         0x10a080x185060x10b600x185b80x1c2de0x10b300x1859c0x10b18,
         0x1858e0x10b0c0x10b060x10bb80x185de0x10b9c0x10b8e0x10bde,
         0x18d400x1c6b00x1e35c0x18d200x1c6980x18d100x1c68c0x18d08,
         0x1c6860x18d040x109400x184b00x1c25c0x11b400x109200x1c6dc,
         0x1c24e0x11b200x18d980x1c6ce0x11b100x109080x184860x11b08,
         0x18d860x109020x109b00x184dc0x11bb00x109980x184ce0x11b98,
         0x18dce0x11b8c0x109860x109dc0x11bdc0x109ce0x11bce0x1cea0,
         0x1e7580x1f3ae0x1ce900x1e74c0x1ce880x1e7460x1ce840x1ce82,
         0x18ca00x1c6580x19da00x18c900x1c64c0x19d900x1cecc0x1c646,
         0x19d880x18c840x19d840x18c820x19d820x108a00x184580x119a0,
         0x108900x1c66e0x13ba00x119900x18ccc0x184460x13b900x19dcc,
         0x108840x13b880x119840x108820x119820x108d80x1846e0x119d8,
         0x108cc0x13bd80x119cc0x108c60x13bcc0x119c60x108ee0x119ee,
         0x13bee0x1ef500x1f7ac0x1ef480x1f7a60x1ef440x1ef420x1ce50,
         0x1e72c0x1ded00x1ef6c0x1e7260x1dec80x1ef660x1dec40x1ce42,
         0x1dec20x18c500x1c62c0x19cd00x18c480x1c6260x1bdd00x19cc8,
         0x1ce660x1bdc80x1dee60x18c420x1bdc40x19cc20x1bdc20x10850,
         0x1842c0x118d00x108480x184260x139d00x118c80x18c660x17bd0,
         0x139c80x19ce60x108420x17bc80x1bde60x118c20x17bc40x1086c,
         0x118ec0x108660x139ec0x118e60x17bec0x139e60x17be60x1ef28,
         0x1f7960x1ef240x1ef220x1ce280x1e7160x1de680x1ef360x1de64,
         0x1ce220x1de620x18c280x1c6160x19c680x18c240x1bce80x19c64,
         0x18c220x1bce40x19c620x1bce20x108280x184160x118680x18c36,
         0x138e80x118640x108220x179e80x138e40x118620x179e40x138e2,
         0x179e20x118760x179f60x1ef120x1de340x1de320x19c340x1bc74,
         0x1bc720x118340x138740x178f40x178f20x105400x105200x18298,
         0x105100x105080x105040x105b00x105980x1058c0x105860x105dc,
         0x105ce0x186a00x186900x1c34c0x186880x1c3460x186840x18682,
         0x104a00x182580x10da00x186d80x1824c0x10d900x186cc0x10d88,
         0x186c60x10d840x104820x10d820x104d80x1826e0x10dd80x186ee,
         0x10dcc0x104c60x10dc60x104ee0x10dee0x1c7500x1c7480x1c744,
         0x1c7420x186500x18ed00x1c76c0x1c3260x18ec80x1c7660x18ec4,
         0x186420x18ec20x104500x10cd00x104480x182260x11dd00x10cc8,
         0x104440x11dc80x10cc40x104420x11dc40x10cc20x1046c0x10cec,
         0x104660x11dec0x10ce60x11de60x1e7a80x1e7a40x1e7a20x1c728,
         0x1cf680x1e7b60x1cf640x1c7220x1cf620x186280x1c3160x18e68,
         0x1c7360x19ee80x18e640x186220x19ee40x18e620x19ee20x10428,
         0x182160x10c680x186360x11ce80x10c640x104220x13de80x11ce4,
         0x10c620x13de40x11ce20x104360x10c760x11cf60x13df60x1f7d4,
         0x1f7d20x1e7940x1efb40x1e7920x1efb20x1c7140x1cf340x1c712,
         0x1df740x1cf320x1df720x186140x18e340x186120x19e740x18e32,
         0x1bef4
    }{
        0x1f5600x1fab80x1ea400x1f5300x1fa9c0x1ea200x1f5180x1fa8e,
        0x1ea100x1f50c0x1ea080x1f5060x1ea040x1eb600x1f5b80x1fade,
        0x1d6400x1eb300x1f59c0x1d6200x1eb180x1f58e0x1d6100x1eb0c,
        0x1d6080x1eb060x1d6040x1d7600x1ebb80x1f5de0x1ae400x1d730,
        0x1eb9c0x1ae200x1d7180x1eb8e0x1ae100x1d70c0x1ae080x1d706,
        0x1ae040x1af600x1d7b80x1ebde0x15e400x1af300x1d79c0x15e20,
        0x1af180x1d78e0x15e100x1af0c0x15e080x1af060x15f600x1afb8,
        0x1d7de0x15f300x1af9c0x15f180x1af8e0x15f0c0x15fb80x1afde,
        0x15f9c0x15f8e0x1e9400x1f4b00x1fa5c0x1e9200x1f4980x1fa4e,
        0x1e9100x1f48c0x1e9080x1f4860x1e9040x1e9020x1d3400x1e9b0,
        0x1f4dc0x1d3200x1e9980x1f4ce0x1d3100x1e98c0x1d3080x1e986,
        0x1d3040x1d3020x1a7400x1d3b00x1e9dc0x1a7200x1d3980x1e9ce,
        0x1a7100x1d38c0x1a7080x1d3860x1a7040x1a7020x14f400x1a7b0,
        0x1d3dc0x14f200x1a7980x1d3ce0x14f100x1a78c0x14f080x1a786,
        0x14f040x14fb00x1a7dc0x14f980x1a7ce0x14f8c0x14f860x14fdc,
        0x14fce0x1e8a00x1f4580x1fa2e0x1e8900x1f44c0x1e8880x1f446,
        0x1e8840x1e8820x1d1a00x1e8d80x1f46e0x1d1900x1e8cc0x1d188,
        0x1e8c60x1d1840x1d1820x1a3a00x1d1d80x1e8ee0x1a3900x1d1cc,
        0x1a3880x1d1c60x1a3840x1a3820x147a00x1a3d80x1d1ee0x14790,
        0x1a3cc0x147880x1a3c60x147840x147820x147d80x1a3ee0x147cc,
        0x147c60x147ee0x1e8500x1f42c0x1e8480x1f4260x1e8440x1e842,
        0x1d0d00x1e86c0x1d0c80x1e8660x1d0c40x1d0c20x1a1d00x1d0ec,
        0x1a1c80x1d0e60x1a1c40x1a1c20x143d00x1a1ec0x143c80x1a1e6,
        0x143c40x143c20x143ec0x143e60x1e8280x1f4160x1e8240x1e822,
        0x1d0680x1e8360x1d0640x1d0620x1a0e80x1d0760x1a0e40x1a0e2,
        0x141e80x1a0f60x141e40x141e20x1e8140x1e8120x1d0340x1d032,
        0x1a0740x1a0720x1e5400x1f2b00x1f95c0x1e5200x1f2980x1f94e,
        0x1e5100x1f28c0x1e5080x1f2860x1e5040x1e5020x1cb400x1e5b0,
        0x1f2dc0x1cb200x1e5980x1f2ce0x1cb100x1e58c0x1cb080x1e586,
        0x1cb040x1cb020x197400x1cbb00x1e5dc0x197200x1cb980x1e5ce,
        0x197100x1cb8c0x197080x1cb860x197040x197020x12f400x197b0,
        0x1cbdc0x12f200x197980x1cbce0x12f100x1978c0x12f080x19786,
        0x12f040x12fb00x197dc0x12f980x197ce0x12f8c0x12f860x12fdc,
        0x12fce0x1f6a00x1fb580x16bf00x1f6900x1fb4c0x169f80x1f688,
        0x1fb460x168fc0x1f6840x1f6820x1e4a00x1f2580x1f92e0x1eda0,
        0x1e4900x1fb6e0x1ed900x1f6cc0x1f2460x1ed880x1e4840x1ed84,
        0x1e4820x1ed820x1c9a00x1e4d80x1f26e0x1dba00x1c9900x1e4cc,
        0x1db900x1edcc0x1e4c60x1db880x1c9840x1db840x1c9820x1db82,
        0x193a00x1c9d80x1e4ee0x1b7a00x193900x1c9cc0x1b7900x1dbcc,
        0x1c9c60x1b7880x193840x1b7840x193820x1b7820x127a00x193d8,
        0x1c9ee0x16fa00x127900x193cc0x16f900x1b7cc0x193c60x16f88,
        0x127840x16f840x127820x127d80x193ee0x16fd80x127cc0x16fcc,
        0x127c60x16fc60x127ee0x1f6500x1fb2c0x165f80x1f6480x1fb26,
        0x164fc0x1f6440x1647e0x1f6420x1e4500x1f22c0x1ecd00x1e448,
        0x1f2260x1ecc80x1f6660x1ecc40x1e4420x1ecc20x1c8d00x1e46c,
        0x1d9d00x1c8c80x1e4660x1d9c80x1ece60x1d9c40x1c8c20x1d9c2,
        0x191d00x1c8ec0x1b3d00x191c80x1c8e60x1b3c80x1d9e60x1b3c4,
        0x191c20x1b3c20x123d00x191ec0x167d00x123c80x191e60x167c8,
        0x1b3e60x167c40x123c20x167c20x123ec0x167ec0x123e60x167e6,
        0x1f6280x1fb160x162fc0x1f6240x1627e0x1f6220x1e4280x1f216,
        0x1ec680x1f6360x1ec640x1e4220x1ec620x1c8680x1e4360x1d8e8,
        0x1c8640x1d8e40x1c8620x1d8e20x190e80x1c8760x1b1e80x1d8f6,
        0x1b1e40x190e20x1b1e20x121e80x190f60x163e80x121e40x163e4,
        0x121e20x163e20x121f60x163f60x1f6140x1617e0x1f6120x1e414,
        0x1ec340x1e4120x1ec320x1c8340x1d8740x1c8320x1d8720x19074,
        0x1b0f40x190720x1b0f20x120f40x161f40x120f20x161f20x1f60a,
        0x1e40a0x1ec1a0x1c81a0x1d83a0x1903a0x1b07a0x1e2a00x1f158,
        0x1f8ae0x1e2900x1f14c0x1e2880x1f1460x1e2840x1e2820x1c5a0,
        0x1e2d80x1f16e0x1c5900x1e2cc0x1c5880x1e2c60x1c5840x1c582,
        0x18ba00x1c5d80x1e2ee0x18b900x1c5cc0x18b880x1c5c60x18b84,
        0x18b820x117a00x18bd80x1c5ee0x117900x18bcc0x117880x18bc6,
        0x117840x117820x117d80x18bee0x117cc0x117c60x117ee0x1f350,
        0x1f9ac0x135f80x1f3480x1f9a60x134fc0x1f3440x1347e0x1f342,
        0x1e2500x1f12c0x1e6d00x1e2480x1f1260x1e6c80x1f3660x1e6c4,
        0x1e2420x1e6c20x1c4d00x1e26c0x1cdd00x1c4c80x1e2660x1cdc8,
        0x1e6e60x1cdc40x1c4c20x1cdc20x189d00x1c4ec0x19bd00x189c8,
        0x1c4e60x19bc80x1cde60x19bc40x189c20x19bc20x113d00x189ec,
        0x137d00x113c80x189e60x137c80x19be60x137c40x113c20x137c2,
        0x113ec0x137ec0x113e60x137e60x1fba80x175f00x1bafc0x1fba4,
        0x174f80x1ba7e0x1fba20x1747c0x1743e0x1f3280x1f9960x132fc,
        0x1f7680x1fbb60x176fc0x1327e0x1f7640x1f3220x1767e0x1f762,
        0x1e2280x1f1160x1e6680x1e2240x1eee80x1f7760x1e2220x1eee4,
        0x1e6620x1eee20x1c4680x1e2360x1cce80x1c4640x1dde80x1cce4,
        0x1c4620x1dde40x1cce20x1dde20x188e80x1c4760x199e80x188e4,
        0x1bbe80x199e40x188e20x1bbe40x199e20x1bbe20x111e80x188f6,
        0x133e80x111e40x177e80x133e40x111e20x177e40x133e20x177e2,
        0x111f60x133f60x1fb940x172f80x1b97e0x1fb920x1727c0x1723e,
        0x1f3140x1317e0x1f7340x1f3120x1737e0x1f7320x1e2140x1e634,
        0x1e2120x1ee740x1e6320x1ee720x1c4340x1cc740x1c4320x1dcf4,
        0x1cc720x1dcf20x188740x198f40x188720x1b9f40x198f20x1b9f2,
        0x110f40x131f40x110f20x173f40x131f20x173f20x1fb8a0x1717c,
        0x1713e0x1f30a0x1f71a0x1e20a0x1e61a0x1ee3a0x1c41a0x1cc3a,
        0x1dc7a0x1883a0x1987a0x1b8fa0x1107a0x130fa0x171fa0x170be,
        0x1e1500x1f0ac0x1e1480x1f0a60x1e1440x1e1420x1c2d00x1e16c,
        0x1c2c80x1e1660x1c2c40x1c2c20x185d00x1c2ec0x185c80x1c2e6,
        0x185c40x185c20x10bd00x185ec0x10bc80x185e60x10bc40x10bc2,
        0x10bec0x10be60x1f1a80x1f8d60x11afc0x1f1a40x11a7e0x1f1a2,
        0x1e1280x1f0960x1e3680x1e1240x1e3640x1e1220x1e3620x1c268,
        0x1e1360x1c6e80x1c2640x1c6e40x1c2620x1c6e20x184e80x1c276,
        0x18de80x184e40x18de40x184e20x18de20x109e80x184f60x11be8,
        0x109e40x11be40x109e20x11be20x109f60x11bf60x1f9d40x13af8,
        0x19d7e0x1f9d20x13a7c0x13a3e0x1f1940x1197e0x1f3b40x1f192,
        0x13b7e0x1f3b20x1e1140x1e3340x1e1120x1e7740x1e3320x1e772,
        0x1c2340x1c6740x1c2320x1cef40x1c6720x1cef20x184740x18cf4,
        0x184720x19df40x18cf20x19df20x108f40x119f40x108f20x13bf4,
        0x119f20x13bf20x17af00x1bd7c0x17a780x1bd3e0x17a3c0x17a1e,
        0x1f9ca0x1397c0x1fbda0x17b7c0x1393e0x17b3e0x1f18a0x1f39a,
        0x1f7ba0x1e10a0x1e31a0x1e73a0x1ef7a0x1c21a0x1c63a0x1ce7a,
        0x1defa0x1843a0x18c7a0x19cfa0x1bdfa0x1087a0x118fa0x139fa,
        0x179780x1bcbe0x1793c0x1791e0x138be0x179be0x178bc0x1789e,
        0x1785e0x1e0a80x1e0a40x1e0a20x1c1680x1e0b60x1c1640x1c162,
        0x182e80x1c1760x182e40x182e20x105e80x182f60x105e40x105e2,
        0x105f60x1f0d40x10d7e0x1f0d20x1e0940x1e1b40x1e0920x1e1b2,
        0x1c1340x1c3740x1c1320x1c3720x182740x186f40x182720x186f2,
        0x104f40x10df40x104f20x10df20x1f8ea0x11d7c0x11d3e0x1f0ca,
        0x1f1da0x1e08a0x1e19a0x1e3ba0x1c11a0x1c33a0x1c77a0x1823a,
        0x1867a0x18efa0x1047a0x10cfa0x11dfa0x13d780x19ebe0x13d3c,
        0x13d1e0x11cbe0x13dbe0x17d700x1bebc0x17d380x1be9e0x17d1c,
        0x17d0e0x13cbc0x17dbc0x13c9e0x17d9e0x17cb80x1be5e0x17c9c,
        0x17c8e0x13c5e0x17cde0x17c5c0x17c4e0x17c2e0x1c0b40x1c0b2,
        0x181740x181720x102f40x102f20x1e0da0x1c09a0x1c1ba0x1813a,
        0x1837a0x1027a0x106fa0x10ebe0x11ebc0x11e9e0x13eb80x19f5e,
        0x13e9c0x13e8e0x11e5e0x13ede0x17eb00x1bf5c0x17e980x1bf4e,
        0x17e8c0x17e860x13e5c0x17edc0x13e4e0x17ece0x17e580x1bf2e,
        0x17e4c0x17e460x13e2e0x17e6e0x17e2c0x17e260x10f5e0x11f5c,
        0x11f4e0x13f580x19fae0x13f4c0x13f460x11f2e0x13f6e0x13f2c,
        0x13f26
    }{
        0x1abe00x1d5f80x153c00x1a9f00x1d4fc0x151e00x1a8f80x1d47e,
        0x150f00x1a87c0x150780x1fad00x15be00x1adf80x1fac80x159f0,
        0x1acfc0x1fac40x158f80x1ac7e0x1fac20x1587c0x1f5d00x1faec,
        0x15df80x1f5c80x1fae60x15cfc0x1f5c40x15c7e0x1f5c20x1ebd0,
        0x1f5ec0x1ebc80x1f5e60x1ebc40x1ebc20x1d7d00x1ebec0x1d7c8,
        0x1ebe60x1d7c40x1d7c20x1afd00x1d7ec0x1afc80x1d7e60x1afc4,
        0x14bc00x1a5f00x1d2fc0x149e00x1a4f80x1d27e0x148f00x1a47c,
        0x148780x1a43e0x1483c0x1fa680x14df00x1a6fc0x1fa640x14cf8,
        0x1a67e0x1fa620x14c7c0x14c3e0x1f4e80x1fa760x14efc0x1f4e4,
        0x14e7e0x1f4e20x1e9e80x1f4f60x1e9e40x1e9e20x1d3e80x1e9f6,
        0x1d3e40x1d3e20x1a7e80x1d3f60x1a7e40x1a7e20x145e00x1a2f8,
        0x1d17e0x144f00x1a27c0x144780x1a23e0x1443c0x1441e0x1fa34,
        0x146f80x1a37e0x1fa320x1467c0x1463e0x1f4740x1477e0x1f472,
        0x1e8f40x1e8f20x1d1f40x1d1f20x1a3f40x1a3f20x142f00x1a17c,
        0x142780x1a13e0x1423c0x1421e0x1fa1a0x1437c0x1433e0x1f43a,
        0x1e87a0x1d0fa0x141780x1a0be0x1413c0x1411e0x141be0x140bc,
        0x1409e0x12bc00x195f00x1cafc0x129e00x194f80x1ca7e0x128f0,
        0x1947c0x128780x1943e0x1283c0x1f9680x12df00x196fc0x1f964,
        0x12cf80x1967e0x1f9620x12c7c0x12c3e0x1f2e80x1f9760x12efc,
        0x1f2e40x12e7e0x1f2e20x1e5e80x1f2f60x1e5e40x1e5e20x1cbe8,
        0x1e5f60x1cbe40x1cbe20x197e80x1cbf60x197e40x197e20x1b5e0,
        0x1daf80x1ed7e0x169c00x1b4f00x1da7c0x168e00x1b4780x1da3e,
        0x168700x1b43c0x168380x1b41e0x1681c0x125e00x192f80x1c97e,
        0x16de00x124f00x1927c0x16cf00x1b67c0x1923e0x16c780x1243c,
        0x16c3c0x1241e0x16c1e0x1f9340x126f80x1937e0x1fb740x1f932,
        0x16ef80x1267c0x1fb720x16e7c0x1263e0x16e3e0x1f2740x1277e,
        0x1f6f40x1f2720x16f7e0x1f6f20x1e4f40x1edf40x1e4f20x1edf2,
        0x1c9f40x1dbf40x1c9f20x1dbf20x193f40x193f20x165c00x1b2f0,
        0x1d97c0x164e00x1b2780x1d93e0x164700x1b23c0x164380x1b21e,
        0x1641c0x1640e0x122f00x1917c0x166f00x122780x1913e0x16678,
        0x1b33e0x1663c0x1221e0x1661e0x1f91a0x1237c0x1fb3a0x1677c,
        0x1233e0x1673e0x1f23a0x1f67a0x1e47a0x1ecfa0x1c8fa0x1d9fa,
        0x191fa0x162e00x1b1780x1d8be0x162700x1b13c0x162380x1b11e,
        0x1621c0x1620e0x121780x190be0x163780x1213c0x1633c0x1211e,
        0x1631e0x121be0x163be0x161700x1b0bc0x161380x1b09e0x1611c,
        0x1610e0x120bc0x161bc0x1209e0x1619e0x160b80x1b05e0x1609c,
        0x1608e0x1205e0x160de0x1605c0x1604e0x115e00x18af80x1c57e,
        0x114f00x18a7c0x114780x18a3e0x1143c0x1141e0x1f8b40x116f8,
        0x18b7e0x1f8b20x1167c0x1163e0x1f1740x1177e0x1f1720x1e2f4,
        0x1e2f20x1c5f40x1c5f20x18bf40x18bf20x135c00x19af00x1cd7c,
        0x134e00x19a780x1cd3e0x134700x19a3c0x134380x19a1e0x1341c,
        0x1340e0x112f00x1897c0x136f00x112780x1893e0x136780x19b3e,
        0x1363c0x1121e0x1361e0x1f89a0x1137c0x1f9ba0x1377c0x1133e,
        0x1373e0x1f13a0x1f37a0x1e27a0x1e6fa0x1c4fa0x1cdfa0x189fa,
        0x1bae00x1dd780x1eebe0x174c00x1ba700x1dd3c0x174600x1ba38,
        0x1dd1e0x174300x1ba1c0x174180x1ba0e0x1740c0x132e00x19978,
        0x1ccbe0x176e00x132700x1993c0x176700x1bb3c0x1991e0x17638,
        0x1321c0x1761c0x1320e0x1760e0x111780x188be0x133780x1113c,
        0x177780x1333c0x1111e0x1773c0x1331e0x1771e0x111be0x133be,
        0x177be0x172c00x1b9700x1dcbc0x172600x1b9380x1dc9e0x17230,
        0x1b91c0x172180x1b90e0x1720c0x172060x131700x198bc0x17370,
        0x131380x1989e0x173380x1b99e0x1731c0x1310e0x1730e0x110bc,
        0x131bc0x1109e0x173bc0x1319e0x1739e0x171600x1b8b80x1dc5e,
        0x171300x1b89c0x171180x1b88e0x1710c0x171060x130b80x1985e,
        0x171b80x1309c0x1719c0x1308e0x1718e0x1105e0x130de0x171de,
        0x170b00x1b85c0x170980x1b84e0x1708c0x170860x1305c0x170dc,
        0x1304e0x170ce0x170580x1b82e0x1704c0x170460x1302e0x1706e,
        0x1702c0x170260x10af00x1857c0x10a780x1853e0x10a3c0x10a1e,
        0x10b7c0x10b3e0x1f0ba0x1e17a0x1c2fa0x185fa0x11ae00x18d78,
        0x1c6be0x11a700x18d3c0x11a380x18d1e0x11a1c0x11a0e0x10978,
        0x184be0x11b780x1093c0x11b3c0x1091e0x11b1e0x109be0x11bbe,
        0x13ac00x19d700x1cebc0x13a600x19d380x1ce9e0x13a300x19d1c,
        0x13a180x19d0e0x13a0c0x13a060x119700x18cbc0x13b700x11938,
        0x18c9e0x13b380x1191c0x13b1c0x1190e0x13b0e0x108bc0x119bc,
        0x1089e0x13bbc0x1199e0x13b9e0x1bd600x1deb80x1ef5e0x17a40,
        0x1bd300x1de9c0x17a200x1bd180x1de8e0x17a100x1bd0c0x17a08,
        0x1bd060x17a040x139600x19cb80x1ce5e0x17b600x139300x19c9c,
        0x17b300x1bd9c0x19c8e0x17b180x1390c0x17b0c0x139060x17b06,
        0x118b80x18c5e0x139b80x1189c0x17bb80x1399c0x1188e0x17b9c,
        0x1398e0x17b8e0x1085e0x118de0x139de0x17bde0x179400x1bcb0,
        0x1de5c0x179200x1bc980x1de4e0x179100x1bc8c0x179080x1bc86,
        0x179040x179020x138b00x19c5c0x179b00x138980x19c4e0x17998,
        0x1bcce0x1798c0x138860x179860x1185c0x138dc0x1184e0x179dc,
        0x138ce0x179ce0x178a00x1bc580x1de2e0x178900x1bc4c0x17888,
        0x1bc460x178840x178820x138580x19c2e0x178d80x1384c0x178cc,
        0x138460x178c60x1182e0x1386e0x178ee0x178500x1bc2c0x17848,
        0x1bc260x178440x178420x1382c0x1786c0x138260x178660x17828,
        0x1bc160x178240x178220x138160x178360x105780x182be0x1053c,
        0x1051e0x105be0x10d700x186bc0x10d380x1869e0x10d1c0x10d0e,
        0x104bc0x10dbc0x1049e0x10d9e0x11d600x18eb80x1c75e0x11d30,
        0x18e9c0x11d180x18e8e0x11d0c0x11d060x10cb80x1865e0x11db8,
        0x10c9c0x11d9c0x10c8e0x11d8e0x1045e0x10cde0x11dde0x13d40,
        0x19eb00x1cf5c0x13d200x19e980x1cf4e0x13d100x19e8c0x13d08,
        0x19e860x13d040x13d020x11cb00x18e5c0x13db00x11c980x18e4e,
        0x13d980x19ece0x13d8c0x11c860x13d860x10c5c0x11cdc0x10c4e,
        0x13ddc0x11cce0x13dce0x1bea00x1df580x1efae0x1be900x1df4c,
        0x1be880x1df460x1be840x1be820x13ca00x19e580x1cf2e0x17da0,
        0x13c900x19e4c0x17d900x1becc0x19e460x17d880x13c840x17d84,
        0x13c820x17d820x11c580x18e2e0x13cd80x11c4c0x17dd80x13ccc,
        0x11c460x17dcc0x13cc60x17dc60x10c2e0x11c6e0x13cee0x17dee,
        0x1be500x1df2c0x1be480x1df260x1be440x1be420x13c500x19e2c,
        0x17cd00x13c480x19e260x17cc80x1be660x17cc40x13c420x17cc2,
        0x11c2c0x13c6c0x11c260x17cec0x13c660x17ce60x1be280x1df16,
        0x1be240x1be220x13c280x19e160x17c680x13c240x17c640x13c22,
        0x17c620x11c160x13c360x17c760x1be140x1be120x13c140x17c34,
        0x13c120x17c320x102bc0x1029e0x106b80x1835e0x1069c0x1068e,
        0x1025e0x106de0x10eb00x1875c0x10e980x1874e0x10e8c0x10e86,
        0x1065c0x10edc0x1064e0x10ece0x11ea00x18f580x1c7ae0x11e90,
        0x18f4c0x11e880x18f460x11e840x11e820x10e580x1872e0x11ed8,
        0x18f6e0x11ecc0x10e460x11ec60x1062e0x10e6e0x11eee0x19f50,
        0x1cfac0x19f480x1cfa60x19f440x19f420x11e500x18f2c0x13ed0,
        0x19f6c0x18f260x13ec80x11e440x13ec40x11e420x13ec20x10e2c,
        0x11e6c0x10e260x13eec0x11e660x13ee60x1dfa80x1efd60x1dfa4,
        0x1dfa20x19f280x1cf960x1bf680x19f240x1bf640x19f220x1bf62,
        0x11e280x18f160x13e680x11e240x17ee80x13e640x11e220x17ee4,
        0x13e620x17ee20x10e160x11e360x13e760x17ef60x1df940x1df92,
        0x19f140x1bf340x19f120x1bf320x11e140x13e340x11e120x17e74,
        0x13e320x17e720x1df8a0x19f0a0x1bf1a0x11e0a0x13e1a0x17e3a,
        0x1035c0x1034e0x107580x183ae0x1074c0x107460x1032e0x1076e,
        0x10f500x187ac0x10f480x187a60x10f440x10f420x1072c0x10f6c,
        0x107260x10f660x18fa80x1c7d60x18fa40x18fa20x10f280x18796,
        0x11f680x18fb60x11f640x10f220x11f620x107160x10f360x11f76,
        0x1cfd40x1cfd20x18f940x19fb40x18f920x19fb20x10f140x11f34,
        0x10f120x13f740x11f320x13f720x1cfca0x18f8a0x19f9a0x10f0a,
        0x11f1a0x13f3a0x103ac0x103a60x107a80x183d60x107a40x107a2,
        0x103960x107b60x187d40x187d20x107940x10fb40x107920x10fb2,
        0x1c7ea
    }};

    private static final int ERROR_LEVEL[][] =
    {{
         27917
    }{
        522568723809
    }{
        237308436284646653428379
    }{
        2745622327555995248011322951164424282954217665
    }{
        361575922525176586640321536742677742687284193517,
        27349426314759380057132080313323139068533063410
    }{
        539422693862771453106610287107505733877381612,
        723476462172430609858822543376511400672762283184,
        4403551931460594225535517352605158651201488502,
        64873371783404972807718406294381843623264543
    }{
        52131086454785858029637953779897444400925749415,
        82293217208928244583620246148447631292908490704,
        51625845790759472367429227296684432686606860569,
        19321912918623628719277527817340379712463646776,
        171491297763156732952704479050748228821808898,
        7846636273783822623806027543368961487432670616,
        15737424272660026937589884545435413081458780434,
        21133053929782786537517834315550868014108539
    }{
        524894757668828577420482586708250905786138720,
        858194311913275190375850438733194280201280828757,
        710814919896856911204796605540913801700799137,
        439418592668353859370694325240216257284549209884,
        31570329793490274877162749812684461334376849521,
        30729180371219358399908103511518517225289470,
        6377316625591726946383073043384858513653890690,
        22907431996559033294980258035558818846210134,
        62832047913073971263318374601192605142673687234,
        7223841777526076404551936897078056414860732621,
        89554426185265530969775575660231773434421726528,
        50311849795321445002388363942805663199647550,
        739143421263268133179262060609441180791893754,
        6053832287497602135429713454834299922191910532,
        60982918920167298724498340241656505579481173,
        404251688954975556425433071599245586485549710
    }{
        3527737350435599428207409574118498285380350492,
        1972659201559142992296432948713068887193352781,
        84675327520435543203666249346781621640268794534,
        5397814083906441024764992906325453785891655241,
        54228912227238380048598752472761107784860658741,
        29020468140785585996248218020297451593913142,
        80868428753656176653899729567744390513192516258,
        24051879439576884851610384168190826328596786303,
        57038141564115623715142953120767671089168304402,
        407085751628642296586184151216447722192358785,
        2883578508368277367079484941145212499851543,
        1527297719524836157832385679728951684466533820,
        669459024521673422441733546365151699591452578,
        3712429833255243427119662777475850764364578911,
        28371147242024528859439451132758977769968843408,
        84238372152156064471455962145873663713159672729,
        62459193417158209563564343693109608563365181772,
        67731024835370841057987061784163286028953635777,
        6185864248337759734626975763269575133124718445,
        787680186640736954492228613830922437519644905,
        78942030544120730089282714153738166251356252341,
        2427978388377202243076316187560310756665397808,
        85130947379537831647915459806590731425216548249,
        32188169953567378221081590530384392228173469791,
        6601624983081554229078171876216425535336286437,
        37527361029618392311666775135362366691379687842,
        3735772074233053992331142424274932154669316,
        34229953410566748864067257654031648672161046656,
        44717161646419053129732176275253317513414381433,
        717451112059628473613864641187766914191945780,
        407164332899165726600325498655357752768223849647,
        6331086325136630428273867541038924431121303263
    }};

    /** Holds value of property outBits. */
    private byte[] outBits;

    /** Holds value of property bitColumns. */
    private int bitColumns;

    /** Holds value of property codeRows. */
    private int codeRows;

    /** Holds value of property codeColumns. */
    private int codeColumns;

    /** Holds value of property codewords. */
    private int[] codewords = new int[MAX_DATA_CODEWORDS + 2];

    /** Holds value of property lenCodewords. */
    private int lenCodewords;

    /** Holds value of property errorLevel. */
    private int errorLevel;

    /** Holds value of property text. */
    private byte[] text;

    /** Holds value of property options. */
    private int options;

    /** Holds value of property aspectRatio. */
    private float aspectRatio;

    /** Holds value of property yHeight. */
    private float yHeight;

    protected static class Segment {
        public char type;
        public int start;
        public int end;

        public Segment(char type, int start, int end) {
            this.type = type;
            this.start = start;
            this.end = end;
        }
    }

    protected static class SegmentList {
        protected ArrayList<Segment> list = new ArrayList<Segment>();

        public void add(char type, int start, int end) {
            list.add(new Segment(type, start, end));
        }

        public Segment get(int idx) {
            if (idx < || idx >= list.size())
                return null;
            return list.get(idx);
        }

        public void remove(int idx) {
            if (idx < || idx >= list.size())
                return;
            list.remove(idx);
        }

        public int size() {
            return list.size();
        }
    }
}