<commit_before>import ArrayHelper from '../common/array_helper.ts';

class BarcodeReader {
    constructor(config, supplements) {
        this._row = [];
        this.config = config || {};
        this.supplements = supplements;
        return this;
    }
    _nextUnset(line, start) {
        var i;
        if (start === undefined) {
            start = 0;
        }
        for (i = start; i < line.length; i++) {
            if (!line[i]) {
                return i;
            }
        }
        return line.length;
    }
    _matchPattern(counter, code, maxSingleError) {
        var i, error = 0, singleError = 0, sum = 0, modulo = 0, barWidth, count, scaled;
        maxSingleError = maxSingleError || this.SINGLE_CODE_ERROR || 1;
        for (i = 0; i < counter.length; i++) {
            sum += counter[i];
            modulo += code[i];
        }
        if (sum < modulo) {
            return Number.MAX_VALUE;
        }
        barWidth = sum / modulo;
        maxSingleError *= barWidth;
        for (i = 0; i < counter.length; i++) {
            count = counter[i];
            scaled = code[i] * barWidth;
            singleError = Math.abs(count - scaled) / scaled;
            if (singleError > maxSingleError) {
                return Number.MAX_VALUE;
            }
            error += singleError;
        }
        return error / modulo;
    }
    _nextSet(line, offset) {
        var i;
        offset = offset || 0;
        for (i = offset; i < line.length; i++) {
            if (line[i]) {
                return i;
            }
        }
        return line.length;
    }
    _correctBars(counter, correction, indices) {
        var length = indices.length, tmp = 0;
        while (length--) {
            tmp = counter[indices[length]] * (1 - ((1 - correction) / 2));
            if (tmp > 1) {
                counter[indices[length]] = tmp;
            }
        }
    }
    _matchTrace(cmpCounter, epsilon) {
        var counter = [], i, self = this, offset = self._nextSet(self._row), isWhite = !self._row[offset], counterPos = 0, bestMatch = {
                error: Number.MAX_VALUE,
                code: -1,
                start: 0,
            }, error;
        if (cmpCounter) {
            for (i = 0; i < cmpCounter.length; i++) {
                counter.push(0);
            }
            for (i = offset; i < self._row.length; i++) {
                if (self._row[i] ^ isWhite) {
                    counter[counterPos]++;
                } else {
                    if (counterPos === counter.length - 1) {
                        error = self._matchPattern(counter, cmpCounter);
                        if (error < epsilon) {
                            bestMatch.start = i - offset;
                            bestMatch.end = i;
                            bestMatch.counter = counter;
                            return bestMatch;
                        } else {
                            return null;
                        }
                    } else {
                        counterPos++;
                    }
                    counter[counterPos] = 1;
                    isWhite = !isWhite;
                }
            }
        } else {
            counter.push(0);
            for (i = offset; i < self._row.length; i++) {
                if (self._row[i] ^ isWhite) {
                    counter[counterPos]++;
                } else {
                    counterPos++;
                    counter.push(0);
                    counter[counterPos] = 1;
                    isWhite = !isWhite;
                }
            }
        }
        // if cmpCounter was not given
        bestMatch.start = offset;
        bestMatch.end = self._row.length - 1;
        bestMatch.counter = counter;
        return bestMatch;
    }
    decodePattern(pattern) {
        var self = this, result;
        self._row = pattern;
        result = self._decode();
        if (result === null) {
            self._row.reverse();
            result = self._decode();
            if (result) {
                result.direction = BarcodeReader.DIRECTION.REVERSE;
                result.start = self._row.length - result.start;
                result.end = self._row.length - result.end;
            }
        } else {
            result.direction = BarcodeReader.DIRECTION.FORWARD;
        }
        if (result) {
            result.format = self.FORMAT;
        }
        return result;
    }
    _matchRange(start, end, value) {
        var i;
        start = start < 0 ? 0 : start;
        for (i = start; i < end; i++) {
            if (this._row[i] !== value) {
                return false;
            }
        }
        return true;
    }
    _fillCounters(offset, end, isWhite) {
        var self = this, counterPos = 0, i, counters = [];
        isWhite = (typeof isWhite !== 'undefined') ? isWhite : true;
        offset = (typeof offset !== 'undefined') ? offset : self._nextUnset(self._row);
        end = end || self._row.length;
        counters[counterPos] = 0;
        for (i = offset; i < end; i++) {
            if (self._row[i] ^ isWhite) {
                counters[counterPos]++;
            } else {
                counterPos++;
                counters[counterPos] = 1;
                isWhite = !isWhite;
            }
        }
        return counters;
    }
    _toCounters(start, counter) {
        var self = this, numCounters = counter.length, end = self._row.length, isWhite = !self._row[start], i, counterPos = 0;
        ArrayHelper.init(counter, 0);
        for (i = start; i < end; i++) {
            if (self._row[i] ^ isWhite) {
                counter[counterPos]++;
            } else {
                counterPos++;
                if (counterPos === numCounters) {
                    break;
                } else {
                    counter[counterPos] = 1;
                    isWhite = !isWhite;
                }
            }
        }
        return counter;
    }
}

Object.defineProperty(BarcodeReader.prototype, 'FORMAT', {
    value: 'unknown',
    writeable: false,
});

BarcodeReader.DIRECTION = {
    FORWARD: 1,
    REVERSE: -1,
};

BarcodeReader.Exception = {
    StartNotFoundException: 'Start-Info was not found!',
    CodeNotFoundException: 'Code could not be found!',
    PatternNotFoundException: 'Pattern could not be found!',
};

BarcodeReader.CONFIG_KEYS = {};
<commit_msg>barcode_reader now in typescript<commit_after>import ArrayHelper from '../common/array_helper';

export enum BarcodeDirection {
    Forward = 1,
    Reverse = -1,
};

export type BarcodeReaderType = string;
export type BarcodeFormat = string;

export interface BarcodeReaderConfig {
    normalizeBarSpaceWidth?: boolean,
    supplements?: Array<BarcodeReaderType>,
};

export interface BarcodeCorrection {
    bar: number,
    space: number,
};

export interface BarcodeInfo {
    code: number,
    correction: BarcodeCorrection,
    end: number,
    endCounter: number,
    error: number,
    start: number,
    startCounter: number,
};

export interface Barcode {
    code: string,
    codeset: number,
    correction: BarcodeCorrection,
    decodedCodes?: Array<string | BarcodeInfo>,
    direction: BarcodeDirection,
    end: number,
    endInfo: BarcodeInfo,
    format: BarcodeFormat,
    start: number,
    startInfo: BarcodeInfo,
    supplement: Barcode,
};

export abstract class BarcodeReader {
    _row: Array<number> = [];
    config = {};
    supplements: Array<BarcodeReader> = [];
    SINGLE_CODE_ERROR = 0;
    FORMAT = 'unknown';
    CONFIG_KEYS = {};

    abstract _decode(row?: Array<number>, start?: number): Barcode;
    static get Exception() {
        return {
            StartNotFoundException: 'Start-Info was not found!',
            CodeNotFoundException: 'Code could not be found!',
            PatternNotFoundException: 'Pattern could not be found!'
        };
    }

    constructor(config: BarcodeReaderConfig, supplements?: Array<BarcodeReader>) {

        this._row = [];
        this.config = config || {};
        if (supplements) {
            this.supplements = supplements;
        }
        return this;
    }

    _nextUnset(line: ReadonlyArray<number>, start: number = 0): number {
        for (let i = start; i < line.length; i++) {
            if (!line[i]) return i;
        }
        return line.length;
    }

    _matchPattern(counter: ReadonlyArray<number>, code: ReadonlyArray<number>, maxSingleError?: number): number {
        let error = 0;
        let singleError = 0;
        let sum = 0;
        let modulo = 0;
        let barWidth = 0;
        let count = 0;
        let scaled = 0;

        maxSingleError = maxSingleError || this.SINGLE_CODE_ERROR || 1;

        for (let i = 0; i < counter.length; i++) {
            sum += counter[i];
            modulo += code[i];
        }
        if (sum < modulo) {
            return Number.MAX_VALUE;
        }

        barWidth = sum / modulo;
        maxSingleError *= barWidth;
        for (let i = 0; i < counter.length; i++) {
            count = counter[i];
            scaled = code[i] * barWidth;
            singleError = Math.abs(count - scaled) / scaled;
            if (singleError > maxSingleError) {
                return Number.MAX_VALUE;
            }
            error += singleError;
        }
        return error / modulo;
    }

    _nextSet(line: ReadonlyArray<number>, offset: number = 0) {
        for (let i = offset; i < line.length; i++) {
            if (line[i]) return i;
        }
        return line.length;
    }

    _correctBars(counter: Array<number>, correction: number, indices: Array<number>) {
        let length = indices.length;
        let tmp = 0;
        while (length--) {
            tmp = counter[indices[length]] * (1 - ((1 - correction) / 2));
            if (tmp > 1) {
                counter[indices[length]] = tmp;
            }
        }
    }

    decodePattern(pattern: Array<number>) {
        this._row = pattern;
        let result = this._decode();
        if (result === null) {
            this._row.reverse();
            result = this._decode();
            if (result) {
                result.direction = BarcodeDirection.Reverse;
                result.start = this._row.length - result.start;
                result.end = this._row.length - result.end;
            }
        } else {
            result.direction = BarcodeDirection.Forward;
        }
        if (result) {
            result.format = this.FORMAT;
        }
        return result;
    }

    _matchRange(start: number, end: number, value: number) {
        var i;
        start = start < 0 ? 0 : start;
        for (i = start; i < end; i++) {
            if (this._row[i] !== value) {
                return false;
            }
        }
        return true;
    }

    _fillCounters(offset: number = this._nextUnset(this._row), end: number = this._row.length, isWhite: boolean = true) {
        const counters: Array<number> = [];
        let counterPos = 0;
        counters[counterPos] = 0;
        for (let i = offset; i < end; i++) {
            if (this._row[i] ^ (isWhite ? 1 : 0)) {
                counters[counterPos]++;
            } else {
                counterPos++;
                counters[counterPos] = 1;
                isWhite = !isWhite;
            }
        }
        return counters;
    }

    _toCounters(start: number, counters: Uint16Array) {
        const numCounters = counters.length;
        const end = this._row.length;
        let isWhite = !this._row[start];
        let counterPos = 0;

        ArrayHelper.init(counters, 0);
        for (let i = start; i < end; i++) {
            if (this._row[i] ^ (isWhite ? 1 : 0)) {
                counters[counterPos]++;
            } else {
                counterPos++;
                if (counterPos === numCounters) {
                    break;
                } else {
                    counters[counterPos] = 1;
                    isWhite = !isWhite;
                }
            }
        }
        return counters;
    }
}

{'fraction_non_alphanumeric': 0.11664591116645912, 'fraction_numerical': 0.00572851805728518, 'mean_word_length': 1.4623875715453802, 'pattern_counts': {'":': 0, '<': 39, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6618762', 'n_tokens_mistral': 3477, 'n_tokens_neox': 3343, 'n_words': 828}