<commit_before>var async = require('async');
var phantom = require('phantom');
var Timeout = require('./timeout.js');

function PhantomInstance(options) {
    this.ph = null;
    this.options = options;
};

PhantomInstance.prototype.openURL = function (url, pageBefore, evaluate, evaluateInject, pageAfter, callback) {
    var self = this;

    var task = {
        url: url,
        evaluate: evaluate,
        evaluateInject: evaluateInject,
        pageBefore: pageBefore,
        pageAfter: pageAfter,
        tries: 0
    };

    var taskDone = function (error, result) {
        if (error) {
            if (task.tries >= self.options.retries) {
                callback(error, task, result);
            } else {
                self.queue.push(task, taskDone);
            }
        } else {
            callback(error, task, result);
        }
    };

    this.queue.push(task, taskDone);
};

PhantomInstance.prototype.errors = {
    PAGE_LOAD_FAILED: 'PAGE_LOAD_FAILED',
    PAGE_LOAD_UNKNOWN: 'PAGE_LOAD_UNKNOWN',
    PAGE_LOAD_NO_RESULT: 'PAGE_LOAD_NO_RESULT',
    TIMEOUT: 'PAGE_LOAD_TIMEOUT'
};

PhantomInstance.prototype.init = function (callback) {
    var self = this;
    this.createPhantomProcess(function (ph) {
        self.initQueue();
        callback();
    });
};

PhantomInstance.prototype.initQueue = function () {
    var self = this;

    this.queue = async.queue(function (task, taskCallback) {
        task.tries++;

        var timeout = new Timeout(function () {
            taskCallback(self.errors.TIMEOUT);
        }, self.options.timeout);

        var createPageAction = function (callback) {
            self.ph.createPage(function (page) {
                callback(null, page);
            });
        };

        var setPageSettingsAction = function (page, callback) {
            page.set('viewportSize', self.options.viewport, function () {
                page.set('settings.loadImages', self.options.load_images, function () {
                    page.set('settings.resourceTimeout', self.options.timeout, function () {
                        callback(null, page);
                    });
                });
            });
        };

        var openURLAction = function (page, callback) {
            page.open(task.url, function (status) {

                page.onConsoleMessage(function (msg) {
                    console.log('page console: ' + msg);
                });

                switch (status) {
                    case 'fail':
                        callback(self.errors.PAGE_LOAD_FAILED);
                        break;
                    case 'success':
                        if (task.pageBefore) {
                            task.pageBefore(page, function () {
                                callback(null, page);
                            });
                            return;
                        }

                        callback(null, page);
                        break;
                    default :
                        callback(self.errors.PAGE_LOAD_UNKNOWN);
                        break;
                }
            });
        };

        var evalAction = function (page, callback) {
            page.evaluate(task.evaluate, function (result) {

                if (typeof result === 'undefined') {
                    callback(self.errors.PAGE_LOAD_NO_RESULT);
                    return;
                }

                callback(null, page, result);
            }, task.evaluateInject);
        };

        var afterEvalAction = function (page, result, callback) {
            if (task.pageAfter) {
                task.pageAfter(page, result, function () {
                    callback(null, result);
                });
                return;
            }

            callback(null, result);
        };

        var actions = [
            createPageAction,
            setPageSettingsAction,
            openURLAction,
            evalAction,
            afterEvalAction
        ];

        async.waterfall(actions, function (error, result) {
            if (timeout.cleared === false) {
                timeout.clear();
            } else if (timeout.cleared === true) {
                return; // timeout error already called, you come to late
            }

            taskCallback(error, result);
        });
    }, this.options.parallel_each);
};

PhantomInstance.prototype.createPhantomProcess = function (callback) {
    var self = this;

    var onExit = function () {
        self.queue.pause();
        self.restartPhantomProcess(function () {
            self.queue.resume();
        });
    };

    phantom.create("--web-security=no", "--ignore-ssl-errors=yes", {onExit: onExit}, function (ph) {
        self.ph = ph;
        callback();
    });
};

PhantomInstance.prototype.restartPhantomProcess = function (restartedCallback) {
    var self = this;<commit_msg>if phantom instance crashes before queue is created then you get a undefined<commit_after>var async = require('async');
var phantom = require('phantom');
var Timeout = require('./timeout.js');

function PhantomInstance(options) {
    this.ph = null;
    this.options = options;
};

PhantomInstance.prototype.openURL = function (url, pageBefore, evaluate, evaluateInject, pageAfter, callback) {
    var self = this;

    var task = {
        url: url,
        evaluate: evaluate,
        evaluateInject: evaluateInject,
        pageBefore: pageBefore,
        pageAfter: pageAfter,
        tries: 0
    };

    var taskDone = function (error, result) {
        if (error) {
            if (task.tries >= self.options.retries) {
                callback(error, task, result);
            } else {
                self.queue.push(task, taskDone);
            }
        } else {
            callback(error, task, result);
        }
    };

    this.queue.push(task, taskDone);
};

PhantomInstance.prototype.errors = {
    PAGE_LOAD_FAILED: 'PAGE_LOAD_FAILED',
    PAGE_LOAD_UNKNOWN: 'PAGE_LOAD_UNKNOWN',
    PAGE_LOAD_NO_RESULT: 'PAGE_LOAD_NO_RESULT',
    TIMEOUT: 'PAGE_LOAD_TIMEOUT'
};

PhantomInstance.prototype.init = function (callback) {
    var self = this;
    this.createPhantomProcess(function (ph) {
        self.initQueue();
        callback();
    });
};

PhantomInstance.prototype.initQueue = function () {
    var self = this;

    this.queue = async.queue(function (task, taskCallback) {
        task.tries++;

        var timeout = new Timeout(function () {
            taskCallback(self.errors.TIMEOUT);
        }, self.options.timeout);

        var createPageAction = function (callback) {
            self.ph.createPage(function (page) {
                callback(null, page);
            });
        };

        var setPageSettingsAction = function (page, callback) {
            page.set('viewportSize', self.options.viewport, function () {
                page.set('settings.loadImages', self.options.load_images, function () {
                    page.set('settings.resourceTimeout', self.options.timeout, function () {
                        callback(null, page);
                    });
                });
            });
        };

        var openURLAction = function (page, callback) {
            page.open(task.url, function (status) {

                page.onConsoleMessage(function (msg) {
                    console.log('page console: ' + msg);
                });

                switch (status) {
                    case 'fail':
                        callback(self.errors.PAGE_LOAD_FAILED);
                        break;
                    case 'success':
                        if (task.pageBefore) {
                            task.pageBefore(page, function () {
                                callback(null, page);
                            });
                            return;
                        }

                        callback(null, page);
                        break;
                    default :
                        callback(self.errors.PAGE_LOAD_UNKNOWN);
                        break;
                }
            });
        };

        var evalAction = function (page, callback) {
            page.evaluate(task.evaluate, function (result) {

                if (typeof result === 'undefined') {
                    callback(self.errors.PAGE_LOAD_NO_RESULT);
                    return;
                }

                callback(null, page, result);
            }, task.evaluateInject);
        };

        var afterEvalAction = function (page, result, callback) {
            if (task.pageAfter) {
                task.pageAfter(page, result, function () {
                    callback(null, result);
                });
                return;
            }

            callback(null, result);
        };

        var actions = [
            createPageAction,
            setPageSettingsAction,
            openURLAction,
            evalAction,
            afterEvalAction
        ];

        async.waterfall(actions, function (error, result) {
            if (timeout.cleared === false) {
                timeout.clear();
            } else if (timeout.cleared === true) {
                return; // timeout error already called, you come to late
            }

            taskCallback(error, result);
        });
    }, this.options.parallel_each);
};

PhantomInstance.prototype.createPhantomProcess = function (callback) {
    var self = this;

    var onExit = function () {
        self.queue && self.queue.pause();
        self.restartPhantomProcess(function () {
            self.queue && self.queue.resume();
        });
    };

    phantom.create("--web-security=no", "--ignore-ssl-errors=yes", {onExit: onExit}, function (ph) {
        self.ph = ph;
        callback();
    });
};

PhantomInstance.prototype.restartPhantomProcess = function (restartedCallback) {
{'fraction_non_alphanumeric': 0.11151736745886655, 'fraction_numerical': 0.00020312817387771684, 'mean_word_length': 1.5294117647058822, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '202531', 'n_tokens_mistral': 2579, 'n_tokens_neox': 2452, 'n_words': 504}