function xmldb_offlinequiz_upgrade($oldversion = 0)
{
    global $CFG, $THEME, $DB, $OUTPUT;
    $dbman = $DB->get_manager();
    // And upgrade begins here. For each one, you'll need one
    // Block of code similar to the next one. Please, delete
    // This comment lines once this file start handling proper
    // Upgrade code.
    // ONLY UPGRADE FROM Moodle 1.9.x (module version 2009042100) is supported.
    if ($oldversion < 2009120700) {
        // Define field counter to be added to offlinequiz_i_log.
        $table = new xmldb_table('offlinequiz_i_log');
        $field = new xmldb_field('counter');
        $field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'rawdata');
        // Launch add field counter.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define field corners to be added to offlinequiz_i_log.
        $field = new xmldb_field('corners');
        $field->set_attributes(XMLDB_TYPE_CHAR, '50', null, null, null, null, 'counter');
        // Launch add field corners.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define field pdfintro to be added to offlinequiz.
        $table = new xmldb_table('offlinequiz');
        $field = new xmldb_field('pdfintro');
        $field->set_attributes(XMLDB_TYPE_TEXT, 'small', null, null, null, null, 'intro');
        // Launch add field pdfintro.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2009120700, 'offlinequiz');
    }
    if ($oldversion < 2010082900) {
        // Define table offlinequiz_p_list to be created.
        $table = new xmldb_table('offlinequiz_p_list');
        // Adding fields to table offlinequiz_p_list.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('offlinequiz', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null, null, null);
        $table->add_field('list', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '1');
        // Adding keys to table offlinequiz_p_list.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Launch create table for offlinequiz_p_list.
        $dbman->create_table($table);
        // Define field position to be dropped from offlinequiz_participants.
        $table = new xmldb_table('offlinequiz_participants');
        $field = new xmldb_field('position');
        // Launch drop field position.
        $dbman->drop_field($table, $field);
        // Define field page to be dropped from offlinequiz_participants.
        $table = new xmldb_table('offlinequiz_participants');
        $field = new xmldb_field('page');
        // Launch drop field page.
        $dbman->drop_field($table, $field);
        // Define field list to be added to offlinequiz_participants.
        $table = new xmldb_table('offlinequiz_participants');
        $field = new xmldb_field('list');
        $field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '1', 'userid');
        // Launch add field list.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2010082900, 'offlinequiz');
    }
    if ($oldversion < 2010090600) {
        // Define index offlinequiz (not unique) to be added to offlinequiz_p_list.
        $table = new xmldb_table('offlinequiz_p_list');
        $index = new XMLDBIndex('offlinequiz');
        $index->set_attributes(XMLDB_INDEX_NOTUNIQUE, array('offlinequiz'));
        // Launch add index offlinequiz.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        $index = new XMLDBIndex('list');
        $index->set_attributes(XMLDB_INDEX_NOTUNIQUE, array('list'));
        // Launch add index list.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Define index offlinequiz (not unique) to be added to offlinequiz_participants.
        $table = new xmldb_table('offlinequiz_participants');
        $index = new XMLDBIndex('offlinequiz');
        $index->set_attributes(XMLDB_INDEX_NOTUNIQUE, array('offlinequiz'));
        // Launch add index offlinequiz.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        $index = new XMLDBIndex('list');
        $index->set_attributes(XMLDB_INDEX_NOTUNIQUE, array('list'));
        // Launch add index list.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        $index = new XMLDBIndex('userid');
        $index->set_attributes(XMLDB_INDEX_NOTUNIQUE, array('userid'));
        // Launch add index list.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2010090600, 'offlinequiz');
    }
    if ($oldversion < 2011021400) {
        // Define field fileformat to be added to offlinequiz.
        $table = new xmldb_table('offlinequiz');
        $field = new xmldb_field('fileformat');
        $field->set_attributes(XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'timemodified');
        // Launch add field fileformat.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2011021400, 'offlinequiz');
    }
    if ($oldversion < 2011032900) {
        // Define field page to be added to offlinequiz_i_log.
        $table = new xmldb_table('offlinequiz_i_log');
        $field = new xmldb_field('page');
        $field->set_attributes(XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'corners');
        // Launch add field page.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define field username to be added to offlinequiz_i_log.
        $field = new xmldb_field('username');
        $field->set_attributes(XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'page');
        // Launch add field username.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Define index username (not unique) to be added to offlinequiz_i_log.
        $index = new XMLDBIndex('username');
        $index->set_attributes(XMLDB_INDEX_NOTUNIQUE, array('username'));
        // Launch add index username.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Define field showgrades to be added to offlinequiz.
        $table = new xmldb_table('offlinequiz');
        $field = new xmldb_field('showgrades');
        $field->set_attributes(XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'fileformat');
        // Launch add field showgrades.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2011032900, 'offlinequiz');
    }
    if ($oldversion < 2011081700) {
        // Define field showtutorial to be added to offlinequiz.
        $table = new xmldb_table('offlinequiz');
        $field = new xmldb_field('showtutorial');
        $field->set_attributes(XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'showgrades');
        // Launch add field showtutorial.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2011081700, 'offlinequiz');
    }
    // ------------------------------------------------------
    // UPGRADE for Moodle 2.0 module starts here.
    // ------------------------------------------------------
    // First we do the changes to the main table 'offlinequiz'.
    // ------------------------------------------------------
    if ($oldversion < 2012010100) {
        // Define field docscreated to be added to offlinequiz.
        $table = new xmldb_table('offlinequiz');
        $field = new xmldb_field('docscreated', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'questionsperpage');
        // Conditionally launch add field docscreated.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012010100, 'offlinequiz');
    }
    // Fill the new field docscreated.
    if ($oldversion < 2012010101) {
        $offlinequizzes = $DB->get_records('offlinequiz');
        foreach ($offlinequizzes as $offlinequiz) {
            $dirname = $CFG->dataroot . '/' . $offlinequiz->course . '/moddata/offlinequiz/' . $offlinequiz->id . '/pdfs';
            // If the answer pdf file for group 1 exists then we have created the documents.
            if (file_exists($dirname . '/answer-a.pdf')) {
                $DB->set_field('offlinequiz', 'docscreated', 1, array('id' => $offlinequiz->id));
            }
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012010101, 'offlinequiz');
    }
    if ($oldversion < 2012010105) {
        // Define table offlinequiz_reports to be created.
        $table = new xmldb_table('offlinequiz_reports');
        // Adding fields to table offlinequiz_reports.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
        $table->add_field('displayorder', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('lastcron', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('cron', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('capability', XMLDB_TYPE_CHAR, '255', null, null, null, null);
        // Adding keys to table offlinequiz_reports.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table offlinequiz_reports.
        // $table->add_index('name', XMLDB_INDEX_UNIQUE, array('name'));.
        // Conditionally launch create table for offlinequiz_reports.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        if (!$DB->get_records_sql("SELECT * FROM {offlinequiz_reports} WHERE name = 'overview'", array())) {
            $record = new stdClass();
            $record->name = 'overview';
            $record->displayorder = '10000';
            $DB->insert_record('offlinequiz_reports', $record);
        }
        if (!$DB->get_records_sql("SELECT * FROM {offlinequiz_reports} WHERE name = 'rimport'", array())) {
            $record = new stdClass();
            $record->name = 'rimport';
            $record->displayorder = '9000';
            $DB->insert_record('offlinequiz_reports', $record);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012010105, 'offlinequiz');
    }
    // Now we create all the new tables.
    // Create table offlinequiz_groups.
    if ($oldversion < 2012010200) {
        echo $OUTPUT->notification('Creating new tables', 'notifysuccess');
        // Define table offlinequiz_groups to be created.
        $table = new xmldb_table('offlinequiz_groups');
        // Adding fields to table offlinequiz_groups.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('offlinequizid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('number', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('sumgrades', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, '0');
        $table->add_field('numberofpages', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('templateusageid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        // Adding keys to table offlinequiz_groups.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table offlinequiz_groups.
        $table->add_index('offlinequizid', XMLDB_INDEX_NOTUNIQUE, array('offlinequizid'));
        // Conditionally launch create table for offlinequiz_groups.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012010200, 'offlinequiz');
    }
    // Create table offlinequiz_group_questions.
    if ($oldversion < 2012010300) {
        // Define table offlinequiz_group_questions to be created.
        $table = new xmldb_table('offlinequiz_group_questions');
        // Adding fields to table offlinequiz_group_questions.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('offlinequizid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('offlinegroupid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('questionid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('position', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '1');
        $table->add_field('pagenumber', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, null, null, null);
        $table->add_field('usageslot', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, null, null, null);
        // Adding keys to table offlinequiz_group_questions.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table offlinequiz_group_questions.
        $table->add_index('offlinequiz', XMLDB_INDEX_NOTUNIQUE, array('offlinequizid'));
        // Conditionally launch create table for offlinequiz_group_questions.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012010300, 'offlinequiz');
    }
    if ($oldversion < 2012010400) {
        // Define table offlinequiz_scanned_pages to be created.
        $table = new xmldb_table('offlinequiz_scanned_pages');
        // Adding fields to table offlinequiz_scanned_pages.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('offlinequizid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('resultid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null);
        $table->add_field('filename', XMLDB_TYPE_CHAR, '1000', null, null, null, null);
        $table->add_field('warningfilename', XMLDB_TYPE_CHAR, '1000', null, null, null, null);
        $table->add_field('groupnumber', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, null, null, null);
        $table->add_field('userkey', XMLDB_TYPE_CHAR, '255', null, null, null, null);
        $table->add_field('pagenumber', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, null, null, null);
        $table->add_field('time', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('status', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, null);
        $table->add_field('error', XMLDB_TYPE_CHAR, '255', null, null, null, null);
        $table->add_field('info', XMLDB_TYPE_TEXT, 'medium', null, null, null, null);
        // Adding keys to table offlinequiz_scanned_pages.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table offlinequiz_scanned_pages.
        $table->add_index('offlinequizid', XMLDB_INDEX_NOTUNIQUE, array('offlinequizid'));
        // Conditionally launch create table for offlinequiz_scanned_pages.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012010400, 'offlinequiz');
    }
    if ($oldversion < 2012010500) {
        // Define table offlinequiz_choices to be created.
        $table = new xmldb_table('offlinequiz_choices');
        // Adding fields to table offlinequiz_choices.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('scannedpageid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('slotnumber', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('choicenumber', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('value', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, null);
        // Adding keys to table offlinequiz_choices.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table offlinequiz_choices.
        $table->add_index('scannedpageid', XMLDB_INDEX_NOTUNIQUE, array('scannedpageid'));
        // Conditionally launch create table for offlinequiz_choices.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012010500, 'offlinequiz');
    }
    if ($oldversion < 2012010600) {
        // Define table offlinequiz_page_corners to be created.
        $table = new xmldb_table('offlinequiz_page_corners');
        // Adding fields to table offlinequiz_page_corners.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('scannedpageid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('x', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('y', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('position', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        // Adding keys to table offlinequiz_page_corners.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Conditionally launch create table for offlinequiz_page_corners.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012010600, 'offlinequiz');
    }
    if ($oldversion < 2012010700) {
        // Define table offlinequiz_results to be created.
        $table = new xmldb_table('offlinequiz_results');
        // Adding fields to table offlinequiz_results.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('offlinequizid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('offlinegroupid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('sumgrades', XMLDB_TYPE_NUMBER, '10, 5', null, null, null, null);
        $table->add_field('usageid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('teacherid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('attendant', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('status', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('timestart', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('timefinish', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, '0');
        $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('preview', XMLDB_TYPE_INTEGER, '3', XMLDB_UNSIGNED, null, null, '0');
        // Adding keys to table offlinequiz_results.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Conditionally launch create table for offlinequiz_results.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012010700, 'offlinequiz');
    }
    if ($oldversion < 2012010800) {
        // Define table offlinequiz_scanned_p_pages to be created.
        $table = new xmldb_table('offlinequiz_scanned_p_pages');
        // Adding fields to table offlinequiz_scanned_p_pages.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('offlinequizid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('listnumber', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, null, null, null);
        $table->add_field('filename', XMLDB_TYPE_CHAR, '1000', null, null, null, null);
        $table->add_field('time', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('status', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL, null);
        $table->add_field('error', XMLDB_TYPE_TEXT, 'small', null, null, null, null);
        // Adding keys to table offlinequiz_scanned_p_pages.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Conditionally launch create table for offlinequiz_scanned_p_pages.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012010800, 'offlinequiz');
    }
    if ($oldversion < 2012010900) {
        // Define table offlinequiz_p_choices to be created.
        $table = new xmldb_table('offlinequiz_p_choices');
        // Adding fields to table offlinequiz_p_choices.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('scannedppageid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null);
        $table->add_field('userid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, null, null, null);
        $table->add_field('value', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0');
        // Adding keys to table offlinequiz_p_choices.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Conditionally launch create table for offlinequiz_p_choices.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012010900, 'offlinequiz');
    }
    if ($oldversion < 2012011000) {
        // Define table offlinequiz_p_lists to be created.
        $table = new xmldb_table('offlinequiz_p_lists');
        // Adding fields to table offlinequiz_p_lists.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('offlinequizid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, null, null, null);
        $table->add_field('number', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '1');
        $table->add_field('filename', XMLDB_TYPE_CHAR, '1000', null, null, null, null);
        // Adding keys to table offlinequiz_p_lists.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table offlinequiz_p_lists.
        $table->add_index('offlinequizid', XMLDB_INDEX_NOTUNIQUE, array('offlinequizid'));
        // Conditionally launch create table for offlinequiz_p_lists.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012011000, 'offlinequiz');
    }
    // ------------------------------------------------------
    // New we rename fields in old tables.
    // ------------------------------------------------------
    // Rename fields in offlinequiz_queue table.
    if ($oldversion < 2012020100) {
        echo $OUTPUT->notification('Renaming fields in old tables.', 'notifysuccess');
        // Rename field offlinequiz on table offlinequiz_queue to NEWNAMEGOESHERE.
        $table = new xmldb_table('offlinequiz_queue');
        $field = new xmldb_field('offlinequiz');
        $field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'timefinish');
        // Launch rename field offlinequiz.
        $dbman->rename_field($table, $field, 'offlinequizid');
        $field = new xmldb_field('importadmin');
        $field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, null, null, '0', 'id');
        // Launch rename field importadmin.
        $dbman->rename_field($table, $field, 'importuserid');
        // New status field.
        $field = new xmldb_field('status', XMLDB_TYPE_TEXT, 'small', null, null, null, 'processed', 'timefinish');
        // Conditionally launch add field status.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012020100, 'offlinequiz');
    }
    // Add and rename fields in table offlinquiz_queue_data.
    if ($oldversion < 2012020200) {
        // Define field status to be added to offlinequiz_queue_data.
        $table = new xmldb_table('offlinequiz_queue_data');
        $field = new xmldb_field('status', XMLDB_TYPE_TEXT, 'small', null, XMLDB_NOTNULL, null, 'ok', 'filename');
        // Conditionally launch add field status.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        } else {
            $dbman->change_field_type($table, $field);
            $dbman->change_field_precision($table, $field);
            $dbman->change_field_notnull($table, $field);
            $dbman->change_field_unsigned($table, $field);
        }
        // Add new field 'error'.
        $field = new xmldb_field('error', XMLDB_TYPE_TEXT, 'small', null, null, null, null, 'status');
        // Conditionally launch add field error.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Rename field queue to queueid.
        $field = new xmldb_field('queue', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'id');
        // Launch rename field queueid.
        $dbman->rename_field($table, $field, 'queueid');
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012020200, 'offlinequiz');
    }
    // Rename field list on table offlinequiz_participants to listid.
    if ($oldversion < 2012020300) {
        // Rename field list on table offlinequiz_participants to listid.
        $table = new xmldb_table('offlinequiz_participants');
        $field = new xmldb_field('list', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'id');
        // Launch rename field listid.
        $dbman->rename_field($table, $field, 'listid');
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012020300, 'offlinequiz');
    }
    // Migrate the old lists of participants to the new table offlinequiz_p_lists (with 's').
    if ($oldversion < 2012020400) {
        $oldplists = $DB->get_records('offlinequiz_p_list');
        foreach ($oldplists as $oldplist) {
            $newplist = new StdClass();
            $newplist->offlinequizid = $oldplist->offlinequiz;
            $newplist->name = $oldplist->name;
            $newplist->number = $oldplist->list;
            // NOTE.
            // We don't set filename because we can always recreate the PDF files if needed.
            $newplist->id = $DB->insert_record('offlinequiz_p_lists', $newplist);
            // Get all the participants linked to the old list and link them to the new list in offlinequiz_p_lists.
            if ($oldparts = $DB->get_records('offlinequiz_participants', array('listid' => $oldplist->id))) {
                foreach ($oldparts as $oldpart) {
                    $oldpart->listid = $newplist->id;
                    $DB->update_record('offlinequiz_participants', $oldpart);
                }
            }
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012020400, 'offlinequiz');
    }
    // Check if there are inconsistencies in the DB, i.e. uniqueids used by both quizzes and offlinequizzes.
    if ($oldversion < 2012020410) {
        $sql = 'SELECT uniqueid
        FROM {offlinequiz_attempts} qa WHERE
        EXISTS (SELECT id from {quiz_attempts} where uniqueid = qa.uniqueid)';
        $doubleids = $DB->get_fieldset_sql($sql, array());
        // For each double uniqueid create a new uniqueid and change the fields in the tables.
        // Offlinequiz_attempts, question_sessions and question_states.
        echo $OUTPUT->notification('Fixing ' . count($doubleids) . ' question attempt uniqueids that are not unique', 'notifysuccess');
        foreach ($doubleids as $doubleid) {
            echo $doubleid . ', ';
            if ($usage = $DB->get_record('question_usages', array('id' => $doubleid))) {
                $transaction = $DB->start_delegated_transaction();
                unset($usage->id);
                $usage->id = $DB->insert_record('question_usages', $usage);
                $DB->set_field_select('offlinequiz_attempts', 'uniqueid', $usage->id, 'uniqueid = :oldid', array('oldid' => $doubleid));
                $DB->set_field_select('question_states', 'attempt', $usage->id, 'attempt = :oldid', array('oldid' => $doubleid));
                $DB->set_field_select('question_sessions', 'attemptid', $usage->id, 'attemptid = :oldid', array('oldid' => $doubleid));
                $transaction->allow_commit();
            }
        }
        upgrade_mod_savepoint(true, 2012020410, 'offlinequiz');
    }
    // -----------------------------------------------------
    //  Update the contextid field in question_usages (compare lib/db/upgrade.php lines 6108 following).
    // -----------------------------------------------------
    if ($oldversion < 2012020500) {
        echo $OUTPUT->notification('Fixing question usages context ID', 'notifysuccess');
        // Update the component field if necessary.
        $DB->set_field('question_usages', 'component', 'mod_offlinequiz', array('component' => 'offlinequiz'));
        // Populate the contextid field.
        $offlinequizmoduleid = $DB->get_field('modules', 'id', array('name' => 'offlinequiz'));
        $DB->execute("\n                UPDATE {question_usages} SET contextid = (\n                SELECT ctx.id\n                FROM {context} ctx\n                JOIN {course_modules} cm ON cm.id = ctx.instanceid AND cm.module = {$offlinequizmoduleid}\n                JOIN {offlinequiz_attempts} quiza ON quiza.offlinequiz = cm.instance\n                WHERE ctx.contextlevel = " . CONTEXT_MODULE . "\n                AND quiza.uniqueid = {question_usages}.id)\n                WHERE (\n                SELECT ctx.id\n                FROM {context} ctx\n                JOIN {course_modules} cm ON cm.id = ctx.instanceid AND cm.module = {$offlinequizmoduleid}\n                JOIN {offlinequiz_attempts} quiza ON quiza.offlinequiz = cm.instance\n                WHERE ctx.contextlevel = " . CONTEXT_MODULE . "\n                AND quiza.uniqueid = {question_usages}.id) IS NOT NULL\n                ");
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012020500, 'offlinequiz');
    }
    // -----------------------------------------------------
    //  Now we migrate data from the old to the new tables.
    // -----------------------------------------------------
    // We have to delete redundant question instances from offlinequizzes because they are incompatible with the new code.
    if ($oldversion < 2012030100) {
        echo $OUTPUT->notification('Migrating old offline quizzes to new offline quizzes..', 'notifysuccess');
        require_once $CFG->dirroot . '/mod/offlinequiz/db/upgradelib.php';
        offlinequiz_remove_redundant_q_instances();
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012030100, 'offlinequiz');
    }
    // Migrate all entries in the offlinequiz_group table to the new tables offlinequiz_groups  and offlinequiz_group_questions.
    if ($oldversion < 2012030101) {
        echo $OUTPUT->notification('Creating new offlinequiz groups', 'notifysuccess');
        $offlinequizzes = $DB->get_records('offlinequiz');
        $counter = 0;
        foreach ($offlinequizzes as $offlinequiz) {
            if (!$DB->get_records('offlinequiz_groups', array('offlinequizid' => $offlinequiz->id))) {
                echo '.';
                $counter++;
                flush();
                ob_flush();
                if ($counter % 100 == 0) {
                    echo "<br/>\n";
                    echo $counter;
                }
                $transaction = $DB->start_delegated_transaction();
                $oldgroups = $DB->get_records('offlinequiz_group', array('offlinequiz' => $offlinequiz->id), 'groupid ASC');
                $newgroups = array();
                foreach ($oldgroups as $oldgroup) {
                    $newgroup = new StdClass();
                    $newgroup->offlinequizid = $offlinequiz->id;
                    $newgroup->number = $oldgroup->groupid;
                    $newgroup->sumgrades = $oldgroup->sumgrades;
                    $newgroup->timecreated = time();
                    $newgroup->timemodified = time();
                    // First we need the ID of the new group.
                    if (!($oldid = $DB->get_field('offlinequiz_groups', 'id', array('offlinequizid' => $offlinequiz->id, 'number' => $newgroup->number)))) {
                        $newgroup->id = $DB->insert_record('offlinequiz_groups', $newgroup);
                    } else {
                        $newgroup->id = $oldid;
                    }
                    // Now create an entry in offlinquiz_group_questions for each question in the old group layout.
                    $questions = explode(',', $oldgroup->questions);
                    $position = 1;
                    foreach ($questions as $question) {
                        $groupquestion = new StdClass();
                        $groupquestion->offlinequizid = $offlinequiz->id;
                        $groupquestion->offlinegroupid = $newgroup->id;
                        $groupquestion->questionid = $question;
                        $groupquestion->position = $position++;
                        if (!$DB->get_record('offlinequiz_group_questions', array('offlinequizid' => $offlinequiz->id, 'offlinegroupid' => $newgroup->id, 'questionid' => $question))) {
                            $DB->insert_record('offlinequiz_group_questions', $groupquestion);
                        }
                    }
                    $newgroups[] = $newgroup;
                }
                require_once $CFG->dirroot . '/mod/offlinequiz/evallib.php';
                list($maxquestions, $maxanswers, $formtype, $questionsperpage) = offlinequiz_get_question_numbers($offlinequiz, $newgroups);
                foreach ($newgroups as $newgroup) {
                    // Now we know the number of pages of the group.
                    $newgroup->numberofpages = ceil($maxquestions / ($formtype * 24));
                    $DB->update_record('offlinequiz_groups', $newgroup);
                }
                $transaction->allow_commit();
            }
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012030101, 'offlinequiz');
    }
    // Migrate all entries in the offlinequiz_i_log table to the new tables offlinequiz_scanned_pages, offlinequiz_choices and.
    // Offlinequiz_page_corners. Also migrate the files to the new filesystem.
    // First we mark all offlinequizzes s.t. we upgrade them only once. Many things can go wrong here..
    if ($oldversion < 2012030200) {
        // Define field needsilogupgrade to be added to offlinequiz_attempts.
        $table = new xmldb_table('offlinequiz');
        $field = new xmldb_field('needsilogupgrade', XMLDB_TYPE_INTEGER, '3', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'timeopen');
        // Launch add field needsilogupgrade.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $DB->set_field('offlinequiz', 'needsilogupgrade', 1);
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012030200, 'offlinequiz');
    }
    // Then we mark all offlinequiz_attempts to be upgraded.
    if ($oldversion < 2012030300) {
        // Define field needsupgradetonewqe to be added to offlinequiz_attempts.
        $table = new xmldb_table('offlinequiz_attempts');
        $field = new xmldb_field('needsupgradetonewqe', XMLDB_TYPE_INTEGER, '3', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'sheet');
        // Launch add field needsupgradetonewqe.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        $DB->set_field('offlinequiz_attempts', 'needsupgradetonewqe', 1);
        // Quiz savepoint reached.
        upgrade_mod_savepoint(true, 2012030300, 'offlinequiz');
    }
    // In a first step we upgrade the offlinequiz_attempts exactly like quiz_attempts (see mod/quiz/db/upgrade.php).
    if ($oldversion < 2012030400) {
        $table = new xmldb_table('question_states');
        // Echo "upgrading attempts to new question engine <br/>\n";.
        if ($dbman->table_exists($table)) {
            // NOTE: We need all attemps, also the ones with sheet=1 because the are the groups' template attempts.
            // Now update all the old attempt data.
            $oldrcachesetting = $CFG->rcache;
            $CFG->rcache = false;
            require_once $CFG->dirroot . '/mod/offlinequiz/db/upgradelib.php';
            $upgrader = new offlinequiz_attempt_upgrader();
            $upgrader->convert_all_quiz_attempts();
            $CFG->rcache = $oldrcachesetting;
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012030400, 'offlinequiz');
    }
    // Then we mark all offlinequiz_attempts to be upgraded.
    if ($oldversion < 2012030500) {
        // Define field resultid to be added to offlinequiz_attempts for later reference.
        set_time_limit(3000);
        $table = new xmldb_table('offlinequiz_attempts');
        $field = new xmldb_field('resultid', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0');
        // Launch add field resultid.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Quiz savepoint reached.
        upgrade_mod_savepoint(true, 2012030500, 'offlinequiz');
    }
    // In a second step we convert all offlinequiz_attempts into offlinequiz_results and also upgrade the ilog table.
    if ($oldversion < 2012060101) {
        require_once $CFG->dirroot . '/mod/offlinequiz/db/upgradelib.php';
        $oldrcachesetting = $CFG->rcache;
        $CFG->rcache = false;
        $upgrader = new offlinequiz_ilog_upgrader();
        $upgrader->convert_all_offlinequiz_attempts();
        $CFG->rcache = $oldrcachesetting;
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012060101, 'offlinequiz');
    }
    if ($oldversion < 2012060105) {
        // Changing type of field grade on table offlinequiz_q_instances to number.
        $table = new xmldb_table('offlinequiz_q_instances');
        $field = new xmldb_field('grade', XMLDB_TYPE_NUMBER, '12, 7', null, XMLDB_NOTNULL, null, '0', 'question');
        // Launch change of type for field grade.
        $dbman->change_field_type($table, $field);
        // Launch change of precision for field grade.
        $dbman->change_field_precision($table, $field);
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012060105, 'offlinequiz');
    }
    if ($oldversion < 2012121200) {
        // Define field introformat to be added to offlinequiz.
        $table = new xmldb_table('offlinequiz');
        $field = new xmldb_field('introformat', XMLDB_TYPE_INTEGER, '4', XMLDB_UNSIGNED, XMLDB_NOTNULL, null, '0', 'intro');
        // Conditionally launch add field introformat.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2012121200, 'offlinequiz');
    }
    if ($oldversion < 2013012400) {
        // Define field info to be added to offlinequiz_queue.
        $table = new xmldb_table('offlinequiz_queue');
        $field = new xmldb_field('info', XMLDB_TYPE_TEXT, 'medium', null, null, null, null, 'status');
        // Conditionally launch add field info.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2013012400, 'offlinequiz');
    }
    if ($oldversion < 2013012410) {
        // Define field info to be added to offlinequiz_queue_data.
        $table = new xmldb_table('offlinequiz_queue_data');
        $field = new xmldb_field('info', XMLDB_TYPE_TEXT, 'medium', null, null, null, null, 'error');
        // Conditionally launch add field info.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2013012410, 'offlinequiz');
    }
    if ($oldversion < 2013012500) {
        // Changing type of field grade on table offlinequiz to int.
        $table = new xmldb_table('offlinequiz');
        $field = new xmldb_field('grade', XMLDB_TYPE_NUMBER, '10, 5', null, XMLDB_NOTNULL, null, '0', 'time');
        // Launch change for field grade.
        $dbman->change_field_type($table, $field);
        $dbman->change_field_precision($table, $field);
        $dbman->change_field_unsigned($table, $field);
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2013012500, 'offlinequiz');
    }
    if ($oldversion < 2013041600) {
        // Rename field question on table offlinequiz_q_instances to questionid.
        $table = new xmldb_table('offlinequiz_q_instances');
        $field = new xmldb_field('question', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'offlinequiz');
        // Launch rename field question.
        $dbman->rename_field($table, $field, 'questionid');
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2013041600, 'offlinequiz');
    }
    if ($oldversion < 2013041601) {
        // Rename field offlinequiz on table offlinequiz_q_instances to offlinequizid.
        $table = new xmldb_table('offlinequiz_q_instances');
        $field = new xmldb_field('offlinequiz', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null, 'id');
        // Launch rename field offlinequiz.
        $dbman->rename_field($table, $field, 'offlinequizid');
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2013041601, 'offlinequiz');
    }
    if ($oldversion < 2013061300) {
        // Define table offlinequiz_hotspots to be created.
        $table = new xmldb_table('offlinequiz_hotspots');
        // Adding fields to table offlinequiz_hotspots.
        $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
        $table->add_field('scannedpageid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
        $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null);
        $table->add_field('x', XMLDB_TYPE_NUMBER, '10, 2', null, XMLDB_NOTNULL, null, null);
        $table->add_field('y', XMLDB_TYPE_NUMBER, '10, 2', null, XMLDB_NOTNULL, null, null);
        $table->add_field('blank', XMLDB_TYPE_INTEGER, '1', null, null, null, null);
        $table->add_field('time', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
        // Adding keys to table offlinequiz_hotspots.
        $table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
        // Adding indexes to table offlinequiz_hotspots.
        $table->add_index('scannedpageididx', XMLDB_INDEX_NOTUNIQUE, array('scannedpageid'));
        // Conditionally launch create table for offlinequiz_hotspots.
        if (!$dbman->table_exists($table)) {
            $dbman->create_table($table);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2013061300, 'offlinequiz');
    }
    if ($oldversion < 2013110800) {
        // Define field timecreated to be added to offlinequiz_queue.
        $table = new xmldb_table('offlinequiz_queue');
        $field = new xmldb_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'importuserid');
        // Conditionally launch add field timecreated.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2013110800, 'offlinequiz');
    }
    if ($oldversion < 2013112500) {
        // Define index offlinequiz_userid_idx (not unique) to be added to offlinequiz_results.
        $table = new xmldb_table('offlinequiz_results');
        $index = new xmldb_index('offlinequiz_userid_idx', XMLDB_INDEX_NOTUNIQUE, array('userid'));
        // Conditionally launch add index offlinequiz_userid_idx.
        if (!$dbman->index_exists($table, $index)) {
            $dbman->add_index($table, $index);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2013112500, 'offlinequiz');
    }
    // Moodle v2.8.5+ release upgrade line.
    // Put any upgrade step following this.
    if ($oldversion < 2015060500) {
        // Rename field page on table offlinequiz_group_questions to NEWNAMEGOESHERE.
        $table = new xmldb_table('offlinequiz_group_questions');
        $field = new xmldb_field('pagenumber', XMLDB_TYPE_INTEGER, '4', null, null, null, null, 'position');
        // Launch rename field page.
        $dbman->rename_field($table, $field, 'page');
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2015060500, 'offlinequiz');
    }
    if ($oldversion < 2015060501) {
        // Rename field page on table offlinequiz_group_questions to NEWNAMEGOESHERE.
        $table = new xmldb_table('offlinequiz_group_questions');
        $field = new xmldb_field('usageslot', XMLDB_TYPE_INTEGER, '4', null, null, null, null, 'position');
        // Launch rename field page.
        $dbman->rename_field($table, $field, 'slot');
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2015060501, 'offlinequiz');
    }
    if ($oldversion < 2015060502) {
        // Define field maxmark to be added to offlinequiz_group_questions.
        $table = new xmldb_table('offlinequiz_group_questions');
        $field = new xmldb_field('maxmark', XMLDB_TYPE_NUMBER, '12, 7', null, XMLDB_NOTNULL, null, '1', 'slot');
        // Conditionally launch add field maxmark.
        if (!$dbman->field_exists($table, $field)) {
            $dbman->add_field($table, $field);
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2015060502, 'offlinequiz');
    }
    if ($oldversion < 2015060902) {
        // This upgrade migrates old offlinequiz_q_instances grades (maxgrades) to new
        // maxmark field in offlinequiz_group_questions.
        // It also deletes group questions with questionid 0 (pagebreaks) and inserts the
        // correct page number instead.
        $numofflinequizzes = $DB->count_records('offlinequiz');
        if ($numofflinequizzes > 0) {
            $pbar = new progress_bar('offlinequizquestionstoslots', 500, true);
            $pbar->create();
            $pbar->update(0, $numofflinequizzes, "Upgrading offlinequiz group questions - {0}/{$numofflinequizzes}.");
            $numberdone = 0;
            $offlinequizzes = $DB->get_recordset('offlinequiz', null, 'id', 'id, numgroups');
            foreach ($offlinequizzes as $offlinequiz) {
                $transaction = $DB->start_delegated_transaction();
                $groups = $DB->get_records('offlinequiz_groups', array('offlinequizid' => $offlinequiz->id), 'number', '*');
                $instancesraw = $DB->get_records('offlinequiz_q_instances', array('offlinequizid' => $offlinequiz->id));
                $questioninstances = array();
                foreach ($instancesraw as $instance) {
                    if (!array_key_exists($instance->questionid, $questioninstances)) {
                        $questioninstances[$instance->questionid] = $instance;
                    }
                }
                foreach ($groups as $group) {
                    $groupquestions = $DB->get_records('offlinequiz_group_questions', array('offlinequizid' => $offlinequiz->id, 'offlinegroupid' => $group->id), 'position');
                    // For every group we start on page 1.
                    $currentpage = 1;
                    $currentslot = 1;
                    foreach ($groupquestions as $groupquestion) {
                        $needsupdate = false;
                        if ($groupquestion->questionid == 0) {
                            // We remove the old pagebreaks with questionid==0.
                            $DB->delete_records('offlinequiz_group_questions', array('id' => $groupquestion->id));
                            $currentpage++;
                            continue;
                        }
                        // If the maxmarks in the question instances differs from the default maxmark (1)
                        // of the offlinequiz_group_questions then change it.
                        if (array_key_exists($groupquestion->questionid, $questioninstances) && ($maxmark = floatval($questioninstances[$groupquestion->questionid]->grade)) && abs(floatval($groupquestion->maxmark) - $maxmark) > 0.001) {
                            $groupquestion->maxmark = $maxmark;
                            $needsupdate = true;
                        }
                        // If the page number is not correct, then change it.
                        if ($groupquestion->page != $currentpage) {
                            $groupquestion->page = $currentpage;
                            $needsupdate = true;
                        }
                        // If the slot is not set, then fill it.
                        if (!$groupquestion->slot) {
                            $groupquestion->slot = $currentslot;
                            $needsupdate = true;
                        }
                        if ($needsupdate) {
                            $DB->update_record('offlinequiz_group_questions', $groupquestion);
                        }
                        $currentslot++;
                    }
                }
                // Done with this offlinequiz. Update progress bar.
                $numberdone++;
                $pbar->update($numberdone, $numofflinequizzes, "Upgrading offlinequiz group questions - {$numberdone}/{$numofflinequizzes}.");
                $transaction->allow_commit();
            }
        }
        // Offlinequiz savepoint reached.
        upgrade_mod_savepoint(true, 2015060902, 'offlinequiz');
    }
    // TODO migrate old offlinequiz_q_instances maxmarks to new maxmark field in offlinequiz_group_questions.
    // TODO migrate  offlinequiz_group_questions to fill in page field correctly. For every group use the
    //      position field to find new pages and insert them.
    //      Adapt offlinequiz code to handle missing zeros as pagebreaks.
    return true;
}
Esempio n. 2
0
if (!$options->sheetfeedback and !$options->gradedsheetfeedback) {
    print_error('noaccess', 'offlinequiz', $CFG->wwwroot . '/course/view.php?id=' . $COURSE->id, $scannedpage->offlinequizid);
}
$url = new moodle_url('/mod/offlinequiz/image.php', array('pageid' => $scannedpage->id, 'resultid' => $result->id));
$PAGE->set_url($url);
$PAGE->set_pagelayout('popup');
echo "<style>\n";
echo "body {margin:0px; font-family:Arial,Verdana,Helvetica,sans-serif;}\n";
echo ".imagebutton {width:250px; height:24px; text-align:left; margin-bottom:10px;}\n";
echo "</style>\n";
echo '<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head>';
offlinequiz_load_useridentification();
$offlinequizconfig = get_config('offlinequiz');
$group = $groups[$result->offlinegroupid];
$offlinequiz->groupid = -$group->id;
list($maxquestions, $maxanswers, $formtype, $questionsperpage) = offlinequiz_get_question_numbers($offlinequiz, array($group));
$offlinequizconfig->papergray = $offlinequiz->papergray;
// Load corners from DB.
$dbcorners = $DB->get_records('offlinequiz_page_corners', array('scannedpageid' => $scannedpage->id));
$corners = array();
foreach ($dbcorners as $corner) {
    $corners[] = new oq_point($corner->x, $corner->y);
}
// Initialize a page scanner.
$scanner = new offlinequiz_page_scanner($offlinequiz, $context->id, $maxquestions, $maxanswers);
// Load the stored picture file.
$sheetloaded = $scanner->load_stored_image($scannedpage->filename, $corners);
$pagenumber = $scannedpage->pagenumber;
// Make a first check.
$scanner->check_deleted();
$scanner->calibrate_and_get_group();
Esempio n. 3
0
function offlinequiz_evaluation_cron($jobid = 0, $verbose = false)
{
    global $CFG, $DB;
    raise_memory_limit(MEMORY_EXTRA);
    // Only count the jobs with status processing that have been started in the last 24 hours.
    $expiretime = time() - 86400;
    $runningsql = "SELECT COUNT(*)\n                     FROM {offlinequiz_queue}\n                    WHERE status = 'processing'\n                      AND timestart > :expiretime";
    $runningjobs = $DB->count_records_sql($runningsql, array('expiretime' => $expiretime));
    if ($runningjobs >= OFFLINEQUIZ_MAX_CRON_JOBS) {
        echo "Too many jobs running! Exiting!";
        return;
    }
    // TODO do this properly. Just for testing.
    $sql = "SELECT * FROM {offlinequiz_queue} WHERE status = 'new'";
    $params = array();
    if ($jobid) {
        $sql .= ' AND id = :jobid ';
        $params['jobid'] = $jobid;
    }
    $sql .= " ORDER BY id ASC";
    // If there are no new jobs, we simply exit.
    if (!($jobs = $DB->get_records_sql($sql, $params, 0, OFFLINEQUIZ_TOP_QUEUE_JOBS))) {
        if ($verbose) {
            echo get_string('nothingtodo', 'offlinequiz');
        }
        return;
    }
    $numberofjobs = count($jobs);
    if ($verbose) {
        $pbar = new progress_bar('offlinequizcronbar', 500, true);
        $pbar->create();
        $pbar->update(0, $numberofjobs, "Processing job - {0}/{$numberofjobs}.");
    }
    $numberdone = 0;
    foreach ($jobs as $job) {
        // Check whether the status is still 'new' (might have been changed by other cronjob).
        $transaction = $DB->start_delegated_transaction();
        $status = $DB->get_field('offlinequiz_queue', 'status', array('id' => $job->id));
        if ($status == 'new') {
            $DB->set_field('offlinequiz_queue', 'status', 'processing', array('id' => $job->id));
            $job->timestart = time();
            $DB->set_field('offlinequiz_queue', 'timestart', $job->timestart, array('id' => $job->id));
            $alreadydone = false;
        } else {
            $alreadydone = true;
        }
        $transaction->allow_commit();
        // If the job is still new, process it!
        if (!$alreadydone) {
            // Set up the context for this job.
            if (!($offlinequiz = $DB->get_record('offlinequiz', array('id' => $job->offlinequizid)))) {
                $DB->set_field('offlinequiz_queue', 'status', 'error', array('id' => $job->id));
                $DB->set_field('offlinequiz_queue', 'info', 'offlinequiz not found', array('id' => $job->id));
                continue;
            }
            if (!($course = $DB->get_record('course', array('id' => $offlinequiz->course)))) {
                $DB->set_field('offlinequiz_queue', 'status', 'error', array('id' => $job->id));
                $DB->set_field('offlinequiz_queue', 'info', 'course not found', array('id' => $job->id));
                continue;
            }
            if (!($cm = get_coursemodule_from_instance("offlinequiz", $offlinequiz->id, $course->id))) {
                $DB->set_field('offlinequiz_queue', 'status', 'error', array('id' => $job->id));
                $DB->set_field('offlinequiz_queue', 'info', 'course module found', array('id' => $job->id));
                continue;
            }
            if (!($context = context_module::instance($cm->id))) {
                $DB->set_field('offlinequiz_queue', 'status', 'error', array('id' => $job->id));
                $DB->set_field('offlinequiz_queue', 'info', 'context not found', array('id' => $job->id));
                continue;
            }
            if (!($groups = $DB->get_records('offlinequiz_groups', array('offlinequizid' => $offlinequiz->id), 'number', '*', 0, $offlinequiz->numgroups))) {
                $DB->set_field('offlinequiz_queue', 'status', 'error', array('id' => $job->id));
                $DB->set_field('offlinequiz_queue', 'info', 'no offlinequiz groups found', array('id' => $job->id));
                continue;
            }
            $coursecontext = context_course::instance($course->id);
            offlinequiz_load_useridentification();
            // TODO.
            $jobdata = $DB->get_records_sql("\n                    SELECT *\n                      FROM {offlinequiz_queue_data}\n                     WHERE queueid = :queueid\n                       AND status = 'new'", array('queueid' => $job->id));
            list($maxquestions, $maxanswers, $formtype, $questionsperpage) = offlinequiz_get_question_numbers($offlinequiz, $groups);
            $dirname = '';
            $doubleentry = 0;
            foreach ($jobdata as $data) {
                $starttime = time();
                $DB->set_field('offlinequiz_queue_data', 'status', 'processing', array('id' => $data->id));
                // We remember the directory name to be able to remove it later.
                if (empty($dirname)) {
                    $pathparts = pathinfo($data->filename);
                    $dirname = $pathparts['dirname'];
                }
                set_time_limit(120);
                try {
                    // Create a new scanner for every page.
                    $scanner = new offlinequiz_page_scanner($offlinequiz, $context->id, $maxquestions, $maxanswers);
                    // Try to load the image file.
                    echo 'job ' . $job->id . ': evaluating ' . $data->filename . "\n";
                    $scannedpage = $scanner->load_image($data->filename);
                    if ($scannedpage->status == 'ok') {
                        echo 'job ' . $job->id . ': image loaded ' . $scannedpage->filename . "\n";
                    } else {
                        if ($scannedpage->error == 'filenotfound') {
                            echo 'job ' . $job->id . ': image file not found: ' . $scannedpage->filename . "\n";
                        }
                    }
                    // Unset the origfilename because we don't need it in the DB.
                    unset($scannedpage->origfilename);
                    $scannedpage->offlinequizid = $offlinequiz->id;
                    // If we could load the image file, the status is 'ok', so we can check the page for errors.
                    if ($scannedpage->status == 'ok') {
                        // We autorotate so check_scanned_page will return a potentially new scanner and the scannedpage.
                        list($scanner, $scannedpage) = offlinequiz_check_scanned_page($offlinequiz, $scanner, $scannedpage, $job->importuserid, $coursecontext, true);
                    } else {
                        if (property_exists($scannedpage, 'id') && !empty($scannedpage->id)) {
                            $DB->update_record('offlinequiz_scanned_pages', $scannedpage);
                        } else {
                            $scannedpage->id = $DB->insert_record('offlinequiz_scanned_pages', $scannedpage);
                        }
                    }
                    echo 'job ' . $job->id . ': scannedpage id ' . $scannedpage->id . "\n";
                    // If the status is still 'ok', we can process the answers. This potentially submits the page and
                    // checks whether the result for a student is complete.
                    if ($scannedpage->status == 'ok') {
                        // We can process the answers and submit them if possible.
                        $scannedpage = offlinequiz_process_scanned_page($offlinequiz, $scanner, $scannedpage, $job->importuserid, $questionsperpage, $coursecontext, true);
                        echo 'job ' . $job->id . ': processed answers for ' . $scannedpage->id . "\n";
                    } else {
                        if ($scannedpage->status == 'error' && $scannedpage->error == 'resultexists') {
                            // Already process the answers but don't submit them.
                            $scannedpage = offlinequiz_process_scanned_page($offlinequiz, $scanner, $scannedpage, $job->importuserid, $questionsperpage, $coursecontext, false);
                            // Compare the old and the new result wrt. the choices.
                            $scannedpage = offlinequiz_check_different_result($scannedpage);
                        }
                    }
                    // If there is something to correct then store the hotspots for retrieval in correct.php.
                    if ($scannedpage->status != 'ok' && $scannedpage->error != 'couldnotgrab' && $scannedpage->error != 'notadjusted' && $scannedpage->error != 'grouperror') {
                        $scanner->store_hotspots($scannedpage->id);
                    }
                    if ($scannedpage->status == 'ok' || $scannedpage->status == 'submitted' || $scannedpage->status == 'suspended' || $scannedpage->error == 'missingpages') {
                        // Mark the file as processed.
                        $DB->set_field('offlinequiz_queue_data', 'status', 'processed', array('id' => $data->id));
                    } else {
                        $DB->set_field('offlinequiz_queue_data', 'status', 'error', array('id' => $data->id));
                        $DB->set_field('offlinequiz_queue_data', 'error', $scannedpage->error, array('id' => $data->id));
                    }
                    if ($scannedpage->error == 'doublepage') {
                        $doubleentry++;
                    }
                } catch (Exception $e) {
                    echo 'job ' . $job->id . ': ' . $e->getMessage() . "\n";
                    $DB->set_field('offlinequiz_queue_data', 'status', 'error', array('id' => $data->id));
                    $DB->set_field('offlinequiz_queue_data', 'error', 'couldnotgrab', array('id' => $data->id));
                    $DB->set_field('offlinequiz_queue_data', 'info', $e->getMessage(), array('id' => $data->id));
                    $scannedpage->status = 'error';
                    $scannedpage->error = 'couldnotgrab';
                    if ($scannedpage->id) {
                        $DB->update_record('offlinequiz_scanned_pages', $scannedpage);
                    } else {
                        $DB->insert_record('offlinequiz_scanned_pages', $scannedpage);
                    }
                }
            }
            // End foreach jobdata.
            offlinequiz_update_grades($offlinequiz);
            $job->timefinish = time();
            $DB->set_field('offlinequiz_queue', 'timefinish', $job->timefinish, array('id' => $job->id));
            $job->status = 'finished';
            $DB->set_field('offlinequiz_queue', 'status', 'finished', array('id' => $job->id));
            echo date('Y-m-d-H:i') . ": Import queue with id {$job->id} imported.\n\n";
            if ($user = $DB->get_record('user', array('id' => $job->importuserid))) {
                $mailtext = get_string('importisfinished', 'offlinequiz', format_text($offlinequiz->name, FORMAT_PLAIN));
                // How many pages have been imported successfully.
                $countsql = "SELECT COUNT(id)\n                               FROM {offlinequiz_queue_data}\n                              WHERE queueid = :queueid\n                                AND status = 'processed'";
                $params = array('queueid' => $job->id);
                $mailtext .= "\n\n" . get_string('importnumberpages', 'offlinequiz', $DB->count_records_sql($countsql, $params));
                // How many pages have an error.
                $countsql = "SELECT COUNT(id)\n                               FROM {offlinequiz_queue_data}\n                              WHERE queueid = :queueid\n                                AND status = 'error'";
                $mailtext .= "\n" . get_string('importnumberverify', 'offlinequiz', $DB->count_records_sql($countsql, $params));
                $mailtext .= "\n" . get_string('importnumberexisting', 'offlinequiz', $doubleentry);
                $linkoverview = "{$CFG->wwwroot}/mod/offlinequiz/report.php?q={$job->offlinequizid}&mode=overview";
                $mailtext .= "\n\n" . get_string('importlinkresults', 'offlinequiz', $linkoverview);
                $linkupload = "{$CFG->wwwroot}/mod/offlinequiz/report.php?q={$job->offlinequizid}&mode=rimport";
                $mailtext .= "\n" . get_string('importlinkverify', 'offlinequiz', $linkupload);
                $mailtext .= "\n\n" . get_string('importtimestart', 'offlinequiz', userdate($job->timestart));
                $mailtext .= "\n" . get_string('importtimefinish', 'offlinequiz', userdate($job->timefinish));
                email_to_user($user, $CFG->noreplyaddress, get_string('importmailsubject', 'offlinequiz'), $mailtext);
            }
        }
        // End !alreadydone.
        $numberdone++;
        if ($verbose) {
            ob_flush();
            $pbar->update($numberdone, $numberofjobs, "Processing job - {$numberdone}/{$numberofjobs}.");
        }
    }
    // End foreach.
}
$context = context_module::instance($cm->id);
$coursecontext = context_course::instance($course->id);
require_capability('mod/offlinequiz:viewreports', $context);
$url = new moodle_url('/mod/offlinequiz/correct.php', array('pageid' => $scannedpage->id));
$PAGE->set_url($url);
$PAGE->set_pagelayout('report');
offlinequiz_load_useridentification();
$offlinequizconfig = get_config('offlinequiz');
// Determine the maxanswers and maxquestions for the scannedpage.
$selectedgroups = $groups;
if ($overwrite && $scannedpage->resultid) {
    $result = $DB->get_record('offlinequiz_results', array('id' => $scannedpage->resultid));
    $resultgroup = $DB->get_record('offlinequiz_groups', array('id' => $result->offlinegroupid));
    $selectedgroups = array($resultgroup);
}
list($maxquestions, $maxanswers, $formtype, $questionsperpage) = offlinequiz_get_question_numbers($offlinequiz, $selectedgroups);
// Get the corners either from the request parameters of from the offlinequiz_page_corners table.
$corners = array();
$nodbcorners = false;
if ($action == 'rotate') {
    $corners[0] = new oq_point(853 - required_param('c-3-x', PARAM_INT), 1208 - required_param('c-3-y', PARAM_INT));
    $corners[1] = new oq_point(853 - required_param('c-2-x', PARAM_INT), 1208 - required_param('c-2-y', PARAM_INT));
    $corners[2] = new oq_point(853 - required_param('c-1-x', PARAM_INT), 1208 - required_param('c-1-y', PARAM_INT));
    $corners[3] = new oq_point(853 - required_param('c-0-x', PARAM_INT), 1208 - required_param('c-0-y', PARAM_INT));
    offlinequiz_save_page_corners($scannedpage, $corners);
} else {
    if ($action == 'readjust') {
        $corners[0] = new oq_point(required_param('c-0-x', PARAM_INT) + 7, required_param('c-0-y', PARAM_INT) + 7);
        $corners[1] = new oq_point(required_param('c-1-x', PARAM_INT) + 7, required_param('c-1-y', PARAM_INT) + 7);
        $corners[2] = new oq_point(required_param('c-2-x', PARAM_INT) + 7, required_param('c-2-y', PARAM_INT) + 7);
        $corners[3] = new oq_point(required_param('c-3-x', PARAM_INT) + 7, required_param('c-3-y', PARAM_INT) + 7);
 public function update_all_results_and_logs($offlinequiz)
 {
     global $DB, $CFG;
     $this->prevent_timeout();
     // Now we have to migrate offlinequiz_attempts to offlinequiz_results because
     // we need the new result IDs for the scannedpages.
     // Get all attempts that have already been migrated to the new question engine.
     $attempts = $DB->get_records('offlinequiz_attempts', array('offlinequiz' => $offlinequiz->id, 'needsupgradetonewqe' => 0, 'sheet' => 0));
     $groups = $DB->get_records('offlinequiz_groups', array('offlinequizid' => $offlinequiz->id), 'number', '*', 0, $offlinequiz->numgroups);
     list($maxquestions, $maxanswers, $formtype, $questionsperpage) = offlinequiz_get_question_numbers($offlinequiz, $groups);
     $transaction = $DB->start_delegated_transaction();
     foreach ($attempts as $attempt) {
         $group = $DB->get_record('offlinequiz_groups', array('offlinequizid' => $offlinequiz->id, 'number' => $attempt->groupid));
         $attemptlog = $DB->get_record('offlinequiz_i_log', array('offlinequiz' => $offlinequiz->id, 'attempt' => $attempt->id, 'page' => 0));
         $result = new StdClass();
         $result->offlinequizid = $offlinequiz->id;
         if ($group) {
             $result->offlinegroupid = $group->id;
         }
         $teacherid = $attemptlog->importadmin;
         if (empty($teacherid)) {
             $teacherid = 2;
         }
         $result->userid = $attempt->userid;
         $result->sumgrades = $attempt->sumgrades;
         $result->usageid = $attempt->uniqueid;
         $result->teacherid = $teacherid;
         $result->offlinegroupid = $group->id;
         $result->status = 'complete';
         $result->timestart = $attempt->timestart;
         $result->timefinish = $attempt->timefinish;
         $result->timemodified = $attempt->timemodified;
         if (!($oldresult = $DB->get_record('offlinequiz_results', array('offlinequizid' => $result->offlinequizid, 'userid' => $result->userid)))) {
             $result->id = $DB->insert_record('offlinequiz_results', $result);
         } else {
             $result->id = $oldresult->id;
             $DB->update_record('offlinequiz_results', $result);
         }
         // Save the resultid, s.t. we can still reconstruct the data later.
         $DB->set_field('offlinequiz_attempts', 'resultid', $result->id, array('id' => $attempt->id));
         if ($quba = question_engine::load_questions_usage_by_activity($result->usageid)) {
             $quba->finish_all_questions();
             $slots = $quba->get_slots();
             // Get all the page logs that have contributed to the attempt.
             if ($group->numberofpages == 1) {
                 $pagelogs = array($attemptlog);
             } else {
                 $sql = "SELECT *\n                    FROM {offlinequiz_i_log}\n                    WHERE offlinequiz = :offlinequizid\n                    AND attempt = :attemptid\n                    AND page > 0";
                 $params = array('offlinequizid' => $offlinequiz->id, 'attemptid' => $attempt->id);
                 $pagelogs = $DB->get_records_sql($sql, $params);
             }
             foreach ($pagelogs as $pagelog) {
                 $rawdata = $pagelog->rawdata;
                 $scannedpage = new StdClass();
                 $scannedpage->offlinequizid = $offlinequiz->id;
                 $scannedpage->resultid = $result->id;
                 $scannedpage->filename = $this->get_pic_name($rawdata);
                 $scannedpage->groupnumber = $this->get_group($rawdata);
                 $scannedpage->userkey = $this->get_user_name($rawdata);
                 if ($group->numberofpages == 1) {
                     $scannedpage->pagenumber = 1;
                 } else {
                     $scannedpage->pagenumber = $pagelog->page;
                 }
                 $scannedpage->time = $pagelog->time ? $pagelog->time : time();
                 $scannedpage->status = 'submitted';
                 $scannedpage->error = '';
                 $scannedpage->id = $DB->insert_record('offlinequiz_scanned_pages', $scannedpage);
                 $itemdata = $this->get_item_data($rawdata);
                 $items = explode(',', $itemdata);
                 if (!empty($items)) {
                     // Determine the slice of slots we are interested in.
                     // we start at the top of the page (e.g. 0, 96, etc).
                     $startindex = min(($scannedpage->pagenumber - 1) * $questionsperpage, count($slots));
                     // We end on the bottom of the page or when the questions are gone (e.g., 95, 105).
                     $endindex = min($scannedpage->pagenumber * $questionsperpage, count($slots));
                     $questioncounter = 0;
                     for ($slotindex = $startindex; $slotindex < $endindex; $slotindex++) {
                         $slot = $slots[$slotindex];
                         if (array_key_exists($questioncounter, $items)) {
                             $item = $items[$questioncounter];
                             for ($key = 0; $key < strlen($item); $key++) {
                                 $itemchoice = substr($item, $key, 1);
                                 $choice = new stdClass();
                                 $choice->scannedpageid = $scannedpage->id;
                                 $choice->slotnumber = $slot;
                                 $choice->choicenumber = $key;
                                 if ($itemchoice == '1') {
                                     $choice->value = 1;
                                 } else {
                                     if ($itemchoice == '0') {
                                         $choice->value = 0;
                                     } else {
                                         $choice->value = -1;
                                     }
                                 }
                                 $choice->id = $DB->insert_record('offlinequiz_choices', $choice);
                             }
                         }
                         $questioncounter++;
                     }
                 }
                 $rawcorners = explode(',', $pagelog->corners);
                 if (!empty($rawcorners) && count($rawcorners) > 8) {
                     for ($i = 0; $i < count($rawcorners); $i++) {
                         if ($rawcorners[$i] < 0) {
                             $rawcorners[$i] = 0;
                         }
                         if ($rawcorners[$i] > 2000) {
                             $rawcorners[$i] = 2000;
                         }
                     }
                     $corners = array();
                     $corners[0] = new oq_point($rawcorners[1], $rawcorners[2]);
                     $corners[1] = new oq_point($rawcorners[3], $rawcorners[4]);
                     $corners[2] = new oq_point($rawcorners[5], $rawcorners[6]);
                     $corners[3] = new oq_point($rawcorners[7], $rawcorners[8]);
                     offlinequiz_save_page_corners($scannedpage, $corners);
                 }
             }
         }
     }
     $DB->set_field('offlinequiz', 'needsilogupgrade', 0, array('id' => $offlinequiz->id));
     $transaction->allow_commit();
     // We start a new transaction for the remaining i_log entries.
     $otherlogs = $DB->get_records('offlinequiz_i_log', array('offlinequiz' => $offlinequiz->id, 'attempt' => 0));
     $transaction = $DB->start_delegated_transaction();
     foreach ($otherlogs as $pagelog) {
         list($status, $error) = $this->get_status_and_error($pagelog->error);
         $rawdata = $pagelog->rawdata;
         $groupnumber = $this->get_group($rawdata);
         $intgroup = intval($groupnumber);
         if ($intgroup > 0 && $intgroup <= $offlinequiz->numgroups) {
             $groupnumber = $intgroup;
         } else {
             $groupnumber = 0;
         }
         $scannedpage = new StdClass();
         $scannedpage->offlinequizid = $offlinequiz->id;
         $scannedpage->filename = $this->get_pic_name($rawdata);
         $scannedpage->groupnumber = $groupnumber;
         $scannedpage->userkey = $this->get_user_name($rawdata);
         $scannedpage->pagenumber = $pagelog->page;
         if ($pagelog->time) {
             $scannedpage->time = $pagelog->time;
         } else {
             $scannedpage->time = time();
         }
         $scannedpage->status = $status;
         $scannedpage->error = $error;
         $scannedpage->id = $DB->insert_record('offlinequiz_scanned_pages', $scannedpage);
         // We do not migrate itemdata for the scanned pages with error.
         // We do store the corners though.
         $rawcorners = explode(',', $pagelog->corners);
         if (!empty($rawcorners) && count($rawcorners) > 8) {
             $corners = array();
             $corners[0] = new oq_point($rawcorners[1], $rawcorners[2]);
             $corners[1] = new oq_point($rawcorners[3], $rawcorners[4]);
             $corners[2] = new oq_point($rawcorners[5], $rawcorners[6]);
             $corners[3] = new oq_point($rawcorners[7], $rawcorners[8]);
             offlinequiz_save_page_corners($scannedpage, $corners);
         }
     }
     $transaction->allow_commit();
     return true;
 }