<commit_before>(function (GLOBAL) {
    var JSEpub = function (blob) {
        this.blob = blob;
    }

    GLOBAL.JSEpub = JSEpub;

    JSEpub.prototype = {
        // For mockability
        unzipperConstructor: JSUnzip,
        inflater: JSInflate,

        // None-blocking processing of the EPUB. The notifier callback will
        // get called with a number and a optional info parameter on various
        // steps of the processing:
        //
        //  1: Unzipping
        //  2: Uncompressing file. File name passed as 2nd argument.
        //  3: Reading OPF
        //  4: Post processing
        //  5: Finished!
        processInSteps: function (notifier) {
            notifier(1);
            this.unzipBlob();

            this.files = {};
            this.uncompressNextCompressedFile(notifier);
            // When all files are decompressed, uncompressNextCompressedFile
            // will continue with the next step.
        },

        unzipBlob: function () {
            var unzipper = new this.unzipperConstructor(this.blob);
            if (!unzipper.isZipFile()) {
                throw new Error("Provided file was not a zip file.");
            }

            unzipper.readEntries();
            this.compressedFiles = unzipper.entries;
        },

        uncompressNextCompressedFile: function (notifier) {
            var self = this;
            var compressedFile = this.compressedFiles.shift();
            if (compressedFile) {
                notifier(2, compressedFile.fileName);
                this.uncompressFile(compressedFile);
                this.withTimeout(this.uncompressNextCompressedFile, notifier);
            } else {
                this.didUncompressAllFiles(notifier);
            }
        },
        
        // For mockability
        withTimeout: function (func, notifier) {
            var self = this;
            setTimeout(function () {<commit_msg>More sensible error message if file is not a zip file.<commit_after>(function (GLOBAL) {
    var JSEpub = function (blob) {
        this.blob = blob;
    }

    GLOBAL.JSEpub = JSEpub;

    JSEpub.prototype = {
        // For mockability
        unzipperConstructor: JSUnzip,
        inflater: JSInflate,

        // None-blocking processing of the EPUB. The notifier callback will
        // get called with a number and a optional info parameter on various
        // steps of the processing:
        //
        //  1: Unzipping
        //  2: Uncompressing file. File name passed as 2nd argument.
        //  3: Reading OPF
        //  4: Post processing
        //  5: Finished!
        processInSteps: function (notifier) {
            notifier(1);
            this.unzipBlob();

            this.files = {};
            this.uncompressNextCompressedFile(notifier);
            // When all files are decompressed, uncompressNextCompressedFile
            // will continue with the next step.
        },

        unzipBlob: function () {
            var unzipper = new this.unzipperConstructor(this.blob);
            if (!unzipper.isZipFile()) {
                throw new Error("Invalid EPUB archive format.");
            }

            unzipper.readEntries();
            this.compressedFiles = unzipper.entries;
        },

        uncompressNextCompressedFile: function (notifier) {
            var self = this;
            var compressedFile = this.compressedFiles.shift();
            if (compressedFile) {
                notifier(2, compressedFile.fileName);
                this.uncompressFile(compressedFile);
                this.withTimeout(this.uncompressNextCompressedFile, notifier);
            } else {
                this.didUncompressAllFiles(notifier);
            }
        },
        
        // For mockability
        withTimeout: function (func, notifier) {
            var self = this;
            setTimeout(function () {
{'fraction_non_alphanumeric': 0.08806818181818182, 'fraction_numerical': 0.004132231404958678, 'mean_word_length': 1.6618556701030929, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '2909623', 'n_tokens_mistral': 1026, 'n_tokens_neox': 998, 'n_words': 263}