]> git.mjollnir.org Git - moodle.git/commitdiff
Merged from STABLE
authorthepurpleblob <thepurpleblob>
Fri, 8 Sep 2006 10:27:48 +0000 (10:27 +0000)
committerthepurpleblob <thepurpleblob>
Fri, 8 Sep 2006 10:27:48 +0000 (10:27 +0000)
question/format/blackboard_6/format.php

index 1ae814c15ee26f82eea00a09f87466ea3bd864f8..37281cd326e5c4e4b1764c6c9f28993bdcf307c5 100644 (file)
-<?php
-
-////////////////////////////////////////////////////////////////////////////
-/// Blackboard 6.x Format
-///
-/// This Moodle class provides all functions necessary to import and export
-///
-///
-////////////////////////////////////////////////////////////////////////////
-
-// Based on default.php, included by ../import.php
-
-require_once ("$CFG->libdir/xmlize.php");
-
-class qformat_blackboard_6 extends qformat_default {
-    function provide_import() {
-        return true;
-    }
-    
-    
-    //Function to check and create the needed dir to unzip file to
-    function check_and_create_import_dir($unique_code) {
-
-        global $CFG; 
-
-        $status = $this->check_dir_exists($CFG->dataroot."/temp",true);
-        if ($status) {
-            $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import",true);
-        }
-        if ($status) {
-            $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import/".$unique_code,true);
-        }
-        
-        return $status;
-    }
-    
-    function clean_temp_dir($dir='') {
-        // this needs to be reworked
-        
-        
-        // for now we will just say everything happened okay note that a mess may be piling up in $CFG->dataroot/temp/bbquiz_import
-        return true;
-        
-        if ($dir == '') {
-            $dir = $this->temp_dir;   
-        }
-        $slash = "/";
-
-        // Create arrays to store files and directories
-        $dir_files      = array();
-        $dir_subdirs    = array();
-
-        // Make sure we can delete it
-        chmod($dir, 0777);
-
-        if ((($handle = opendir($dir))) == FALSE) {
-            // The directory could not be opened
-            return false;
-        }
-
-        // Loop through all directory entries, and construct two temporary arrays containing files and sub directories
-        while($entry = readdir($handle)) {
-            if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != ".") {
-                $dir_subdirs[] = $dir. $slash .$entry;
-            }
-            else if ($entry != ".." && $entry != ".") {
-                $dir_files[] = $dir. $slash .$entry;
-            }
-        }
-
-        // Delete all files in the curent directory return false and halt if a file cannot be removed
-        for($i=0; $i<count($dir_files); $i++) {
-            chmod($dir_files[$i], 0777);
-            if (((unlink($dir_files[$i]))) == FALSE) {
-                return false;
-            }
-        }
-
-        // Empty sub directories and then remove the directory
-        for($i=0; $i<count($dir_subdirs); $i++) {
-            chmod($dir_subdirs[$i], 0777);
-            if ($this->clean_temp_dir($dir_subdirs[$i]) == FALSE) {
-                return false;
-            }
-            else {
-                if (rmdir($dir_subdirs[$i]) == FALSE) {
-                return false;
-                }
-            }
-        }
-
-        // Close directory
-        closedir($handle);
-        if (rmdir($this->temp_dir) == FALSE) {
-            return false;    
-        }
-        // Success, every thing is gone return true
-        return true;
-    }
-    
-    //Function to check if a directory exists and, optionally, create it
-    function check_dir_exists($dir,$create=false) {
-
-        global $CFG; 
-
-        $status = true;
-        if(!is_dir($dir)) {
-            if (!$create) {
-                $status = false;
-            } else {
-                umask(0000);
-                $status = mkdir ($dir,$CFG->directorypermissions);
-            }
-        }
-        return $status;
-    }
-
-    function importpostprocess() {
-    /// Does any post-processing that may be desired
-    /// Argument is a simple array of question ids that 
-    /// have just been added.
-    
-        // need to clean up temporary directory
-        return $this->clean_temp_dir();
-    }
-
-    function copy_file_to_course($filename) {
-        global $CFG;
-        global $course;
-        $filename = str_replace('\\','/',$filename);
-        $fullpath = $this->temp_dir.'/res00001/'.$filename;
-        $basename = basename($filename);
-    
-        $copy_to = $CFG->dataroot.'/'.$course->id.'/bb_import';
-        
-        if ($this->check_dir_exists($copy_to,true)) {
-            if(is_readable($fullpath)) {
-                $copy_to.= '/'.$basename;
-                if (!copy($fullpath, $copy_to)) {
-                    return false;
-                }
-                else {
-                    return $copy_to;
-                }
-            }
-        }
-        else {
-            return false;   
-        }
-    }
-
-    function readdata($filename) {
-    /// Returns complete file with an array, one item per line
-        global $CFG;
-        
-        $unique_code = time();
-        $temp_dir = $CFG->dataroot."/temp/bbquiz_import/".$unique_code;
-        $this->temp_dir = $temp_dir;
-        if ($this->check_and_create_import_dir($unique_code)) {
-            if(is_readable($filename)) {
-                if (!copy($filename, "$temp_dir/bboard.zip")) {
-                    error("Could not copy backup file");
-                }
-                if(unzip_file("$temp_dir/bboard.zip", '', false)) {
-                    // assuming that the information is in res0001.dat
-                    // after looking at 6 examples this was always the case
-                    $q_file = "$temp_dir/res00001.dat";
-                    if (is_file($q_file)) {
-                        if (is_readable($q_file)) {
-                            $filearray = file($q_file);
-                            /// Check for Macintosh OS line returns (ie file on one line), and fix
-                            if (ereg("\r", $filearray[0]) AND !ereg("\n", $filearray[0])) {
-                                return explode("\r", $filearray[0]);
-                            } else {
-                                return $filearray;
-                            }
-                            return false;        
-                        }
-                    }
-                    else {
-                        error("Could not find question data file in zip");   
-                    }
-                }
-                else {
-                    print "filename: $filename<br />tempdir: $temp_dir <br />";
-                    error("Could not unzip file.");   
-                }
-            }
-            else {
-                error ("Could not read uploaded file");   
-            }
-        }
-        else {
-            error("Could not create temporary directory");   
-        }
-    }
-        
-    function save_question_options($question) {
-        return true; 
-    }
-    
-    
-    
-  function readquestions ($lines) {
-    /// Parses an array of lines into an array of questions,
-    /// where each item is a question object as defined by
-    /// readquestion(). 
-
-    $text = implode($lines, " ");
-    $xml = xmlize($text, 0);
-
-    $raw_questions = $xml['questestinterop']['#']['assessment'][0]['#']['section'][0]['#']['item'];
-    $questions = array();
-
-    foreach($raw_questions as $quest) {
-        $question = $this->create_raw_question($quest);
-        switch($question->qtype) {
-            case "Matching":
-                $this->process_matching($question, $questions);
-                break;
-            case "Multiple Choice":
-                $this->process_mc($question, $questions);
-                break;
-            case "Essay":
-                $this->process_essay($question, $questions);
-                break;
-            case "Multiple Answer":
-                $this->process_ma($question, $questions);
-                break;
-            case "True/False":
-                $this->process_tf($question, $questions);
-                break;
-            case 'Fill in the Blank':
-                $this->process_fblank($question, $questions);
-                break;
-            default:
-                print "Unknown or unhandled question type: \"$question->qtype\"<br />";
-                break;
-        }
-
-    }
-    //print_object($questions);
-    return $questions;
-  }
-
-
-// creates a cleaner object to deal with for processing into moodle
-// the object created is NOT a moodle question object
-function create_raw_question($quest) {
-    //print_object($quest);
-    $question = $this->defaultquestion();
-    $question->qtype = $quest['#']['itemmetadata'][0]['#']['bbmd_questiontype'][0]['#'];
-    $presentation->blocks = $quest['#']['presentation'][0]['#']['flow'][0]['#']['flow'];
-    foreach($presentation->blocks as $pblock) {
-        
-        $block = NULL;
-        $block->type = $pblock['@']['class'];
-        switch($block->type) {
-            case 'QUESTION_BLOCK':
-                $sub_blocks = $pblock['#']['flow'];
-                foreach($sub_blocks as $sblock) {
-                    $this->process_block($sblock, $block);  
-                }
-                break;
-            case 'RESPONSE_BLOCK':
-                $choices = NULL;
-                switch($question->qtype) {
-                    case 'Matching':
-                        $bb_subquestions = $pblock['#']['flow'];
-                        $sub_questions = array();
-                        foreach($bb_subquestions as $bb_subquestion) {
-                            $sub_question = NULL;
-                            $sub_question->ident = $bb_subquestion['#']['response_lid'][0]['@']['ident'];
-                            $this->process_block($bb_subquestion['#']['flow'][0], $sub_question);
-                            $bb_choices = $bb_subquestion['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];
-                            $choices = array();
-                            $this->process_choices($bb_choices, $choices);
-                            $sub_question->choices = $choices;
-                            if (!isset($block->subquestions)) {
-                                $block->subquestions = array();
-                            }
-                            $block->subquestions[] = $sub_question;
-                        }
-                        break;
-                    case 'Multiple Answer':
-                        $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];
-                        $choices = array();
-                        $this->process_choices($bb_choices, $choices);
-                        $block->choices = $choices;
-                        break;
-                    case 'Essay':
-                        // Doesn't apply since the user responds with text input
-                        break;
-                    case 'Multiple Choice':
-                        $mc_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];
-                        foreach($mc_choices as $mc_choice) {
-                            $choices = NULL;
-                            $this->process_block($mc_choice, $choices);
-                            $block->choices[] = $choices;                            
-                        }
-                        break;
-                    case 'Fill in the Blank':
-                        // do nothing?
-                        break;
-                    default:
-                        $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];
-                        $choices = array();
-                        $this->process_choices($bb_choices, $choices);
-                        $block->choices = $choices;
-                }
-                break;
-            case 'RIGHT_MATCH_BLOCK':
-                $matching_answerset = $pblock['#']['flow'];
-                $answerset = array();
-                foreach($matching_answerset as $answer) {
-                    $this->process_block($answer, $bb_answer);
-                    $answerset[] = $bb_answer;
-                }
-                $block->matching_answerset = $answerset;
-                break;
-            default:
-                print "UNHANDLED PRESENTATION BLOCK";
-                break;
-        }
-        $question->{$block->type} = $block;
-    }
-    
-    // determine response processing 
-    // there is a section called 'outcomes' that I don't know what to do with
-    $resprocessing = $quest['#']['resprocessing'];
-
-    $respconditions = $resprocessing[0]['#']['respcondition'];
-    $reponses = array();
-    if ($question->qtype == 'Matching') {
-        $this->process_matching_responses($respconditions, $responses);
-    }
-    else {
-        $this->process_responses($respconditions, $responses);
-    }
-    $question->responses = $responses;
-    
-    $feedbackset = $quest['#']['itemfeedback'];
-
-    $feedbacks = array();
-    $this->process_feedback($feedbackset, $feedbacks);
-    $question->feedback = $feedbacks;
-
-     return $question;
-}
-
-function process_block($cur_block, &$block) {
-    $cur_type = $cur_block['@']['class'];
-    global $course, $CFG;
-    switch($cur_type) {
-        case 'FORMATTED_TEXT_BLOCK':
-            $block->text = $this->strip_applet_tags_get_mathml($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']);
-            break;
-        case 'FILE_BLOCK':
-            //revisit this to make sure it is working correctly
-            $block->file = $cur_block['#']['material'][0]['#']['matapplication'][0]['@']['uri'];
-            if ($block->file != '') {
-                // if we have a file copy it to the course dir and adjust its name to be visible over the web.
-                $block->file = $this->copy_file_to_course($block->file);
-                $block->file = $CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($block->file);
-            }
-            break;
-        case 'Block':
-            if (isset($cur_block['#']['material'][0]['#']['mattext'][0]['#'])) {
-                $block->text = $cur_block['#']['material'][0]['#']['mattext'][0]['#'];
-            }
-            else if (isset($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'])) {
-                $block->text = $cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'];
-            }
-            else if (isset($cur_block['#']['response_label'])) {
-                // this is a response label block
-                $sub_blocks = $cur_block['#']['response_label'][0];
-                if(!isset($block->ident)) {
-                    if(isset($sub_blocks['@']['ident'])) {
-                        $block->ident = $sub_blocks['@']['ident'];
-                    }
-                }
-                foreach($sub_blocks['#']['flow_mat'] as $sub_block) {
-                    $this->process_block($sub_block, $block);   
-                }
-            }
-            else {
-                if (isset($cur_block['#']['flow_mat']) || isset($cur_block['#']['flow'])) {
-                    if (isset($cur_block['#']['flow_mat'])) {
-                        $sub_blocks = $cur_block['#']['flow_mat'];
-                    }
-                    elseif (isset($cur_block['#']['flow'])) {
-                        $sub_blocks = $cur_block['#']['flow'];
-                    }
-                   foreach ($sub_blocks as $sblock) {
-                        // this will recursively grab the sub blocks which should be of one of the other types
-                        $this->process_block($sblock, $block);
-                    }
-                }
-            }
-            break;
-        case 'LINK_BLOCK':
-            // not sure how this should be included
-            if (!empty($cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'])) {
-                $block->link = $cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'];
-            }
-            else {
-               $block->link = '';
-            }
-            break;    
-    }    
-}
-
-function process_choices($bb_choices, &$choices) {
-    foreach($bb_choices as $choice) {
-        if (isset($choice['@']['ident'])) {
-            $cur_choice = $choice['@']['ident'];
-        }
-        else {
-            $cur_choice = $choice['#']['response_label'][0]['@']['ident'];
-        }
-        if (isset($choice['#']['flow_mat'][0])) {
-            $cur_block = $choice['#']['flow_mat'][0];
-            $this->process_block($cur_block, $cur_choice);
-        }
-        elseif (isset($choice['#']['response_label'])) {
-            $this->process_block($choice, $cur_choice);
-        }
-        $choices[] = $cur_choice;
-    }    
-}
-
-function process_matching_responses($bb_responses, &$responses) {
-    //print_object($bb_responses);
-    foreach($bb_responses as $bb_response) {
-        $response = NULL;
-        if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'])) {
-            $response->correct = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#'];
-            $response->ident = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['@']['respident'];
-        }
-        else {
-            $response->correct =  'Broken Question?';
-            $response->ident = 'Broken Question?';
-        }
-        $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
-        $responses[] = $response;
-    }
-}
-
-function process_responses($bb_responses, &$responses) {
-        foreach($bb_responses as $bb_response) {
-            if (isset($bb_response['@']['title'])) {
-                $response->title = $bb_response['@']['title'];    
-            }
-            else {
-                $reponse->title = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
-            }
-            $reponse->ident = array();
-            if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#'])) {
-                $response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#'];    
-            }
-            else if (isset($bb_response['#']['conditionvar'][0]['#']['other'][0]['#'])) {
-                $response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['other'][0]['#'];  
-            }
-            
-            if (isset($bb_response['#']['conditionvar'][0]['#']['and'][0]['#'])) {
-                $responseset = $bb_response['#']['conditionvar'][0]['#']['and'][0]['#']['varequal'];
-                foreach($responseset as $rs) {
-                    $response->ident[] = $rs['#'];
-                    if(!isset($response->feedback)) {
-                        $response->feedback = $rs['@']['respident'];
-                    }    
-                }
-            }
-            else {
-                $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];   
-            }
-
-            // determine what point value to give response
-            if (isset($bb_response['#']['setvar'])) {
-                switch ($bb_response['#']['setvar'][0]['#']) {
-                    case "SCORE.max":
-                        $response->fraction = 1;
-                        break;
-                    default:
-                        // I have only seen this being 0 or unset  there are probably fractional values of SCORE.max, but I'm not sure what they look like
-                        $response->fraction = 0;
-                        break;
-                }
-            }
-            else {
-               // just going to assume this is the case this is probably not correct.
-               $response->fraction = 0;
-            }
-            
-
-            $responses[] = $response;
-        }
-}
-
-function process_feedback($feedbackset, &$feedbacks) {
-    foreach($feedbackset as $bb_feedback) {
-        $feedback->ident = $bb_feedback['@']['ident'];
-        if (isset($bb_feedback['#']['flow_mat'][0])) {
-            $this->process_block($bb_feedback['#']['flow_mat'][0], $feedback);
-        }
-        elseif (isset($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0])) {
-            $this->process_block($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0], $feedback);
-        }
-        $feedbacks[] = $feedback;
-    }
-}
-
-//----------------------------------------
-// Process True / False Questions
-//----------------------------------------
-function process_tf($quest, &$questions) {
-    $question = $this->defaultquestion();
-
-    $question->qtype = TRUEFALSE;
-    $question->defaultgrade = 1;
-    $question->single = 1; // Only one answer is allowed
-    $question->image = ""; // No images with this format
-    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
-    // put name in question object
-    $question->name = $question->questiontext;
-
-    // first choice is true, second is false.
-    if ($quest->responses[0]->fraction == 1) {
-        $correct = true;    
-    }
-    else {
-        $correct = false;   
-    }
-    
-    foreach($quest->feedback as $fb) {
-        $fback->{$fb->ident} = $fb->text;   
-    }
-    
-    if ($correct) {  // true is correct
-        $question->answer = 1;
-        $question->feedbacktrue = addslashes($fback->correct);
-        $question->feedbackfalse = addslashes($fback->incorrect);
-    } else {  // false is correct
-        $question->answer = 0;
-        $question->feedbacktrue = addslashes($fback->incorrect);
-        $question->feedbackfalse = addslashes($fback->correct);
-    }
-    $questions[] = $question;
-}
-
-
-//----------------------------------------
-// Process Fill in the Blank
-//----------------------------------------
-function process_fblank($quest, &$questions) {
-    $question = $this->defaultquestion();
-    $question->qtype = SHORTANSWER;
-    $question->defaultgrade = 1;
-    $question->single = 1;
-    $question->usecase = 0;
-    $question->image = '';
-    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
-    $question->name = $question->questiontext;
-    $answers = array();
-    $fractions = array();
-    $feedbacks = array();
-    
-    // extract the feedback
-    $feedback = array();
-    foreach($quest->feedback as $fback) {
-        if (isset($fback->ident)) {
-            $feedback[$fback->ident] = $fback->text;
-        }
-    }
-    
-    foreach($quest->responses as $response) {
-        if(isset($response->title)) {
-            $answers[] = addslashes($response->ident[0]);
-            $fractions[] = $response->fraction;
-            if (isset($feedback[$response->feedback])) {
-                $feedbacks[] = addslashes($feedback[$response->feedback]);
-            }
-            else {
-                $feedbacks[] = '';
-            }
-        }
-    }
-    
-    $question->answer = $answers;
-    $question->fraction = $fractions;
-    $question->feedback = $feedback;
-
-    if (isset($question) && $question != '') {
-        $questions[] = $question;
-    }
-
-}
-
-//----------------------------------------
-// Process Multiple Choice Questions
-//----------------------------------------
-function process_mc($quest, &$questions) {
-    $question = $this->defaultquestion();
-    $question->qtype = MULTICHOICE;
-    $question->defaultgrade = 1;
-    $question->single = 1;
-    $question->image = "";
-    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
-    $question->name = $question->questiontext;
-    
-    $feedback = array();
-    foreach($quest->feedback as $fback) {
-        $feedback[$fback->ident] = addslashes($fback->text);
-    }
-
-    
-    foreach($quest->responses as $response) {
-        if (isset($response->title)) {
-            if ($response->title == 'correct') {
-                // only one answer possible for this qtype so first index is correct answer
-                $correct = $response->ident[0];
-            }
-        }
-        else {
-            // fallback method for when the title is not set
-            if ($response->feedback == 'correct') {
-               // only one answer possible for this qtype so first index is correct answer
-               $correct = $response->ident[0];
-            }
-        }
-    }
-
-    $i = 0;
-    foreach($quest->RESPONSE_BLOCK->choices as $response) {
-        $question->answer[$i] = addslashes($response->text);
-        if ($correct == $response->ident) {
-            $question->fraction[$i] = 1;
-            // this is a bit of a hack to catch the feedback... first we see if a 'correct' feedback exists
-            // then specific feedback for this question (maybe this should be switched?, but from my example
-            // question pools I have not seen response specific feedback, only correct or incorrect feedback
-            if (!empty($feedback['correct'])) {
-                $question->feedback[$i] = $feedback['correct'];
-            }
-            elseif (!empty($feedback[$i])) {
-                $question->feedback[$i] = $feedback[$i];
-            }
-            else {
-                // failsafe feedback (should be '' instead?)
-                $question->feedback[$i] = "correct";   
-            }
-        }    
-        else {
-            $question->fraction[$i] = 0;
-            if (!empty($feedback['incorrect'])) {
-                $question->feedback[$i] = $feedback['incorrect'];
-            }
-            elseif (!empty($feedback[$i])) {
-                $question->feedback[$i] = $feedback[$i];
-            }
-            else {
-                // failsafe feedback (should be '' instead?)
-                $question->feedback[$i] = 'incorrect';
-            }
-        }
-        $i++;
-    }
-
-    if (isset($question) && $question != '') {
-        $questions[] = $question;
-    }
-}
-
-//----------------------------------------
-// Process Multiple Choice Questions With Multiple Answers
-//----------------------------------------
-function process_ma($quest, &$questions) {
-
-    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
-    $question->name = $question->questiontext; 
-    $question->qtype = MULTICHOICE;
-    $question->defaultgrade = 1;
-    $question->single = 0; // More than one answers allowed
-    $question->image = ""; // No images with this format
-
-    $answers = $quest->responses;
-    $correct_answers = array();
-    foreach($answers as $answer) {
-        if($answer->title == 'correct') {
-            $answerset = $answer->ident;
-            foreach($answerset as $ans) {
-                $correct_answers[] = $ans;
-            }
-        }
-    }
-    
-    foreach ($quest->feedback as $fb) {
-        $feedback->{$fb->ident} = addslashes(trim($fb->text));
-    }
-    
-    $correct_answer_count = count($correct_answers);
-    $choiceset = $quest->RESPONSE_BLOCK->choices;
-    $i = 0;
-    foreach($choiceset as $choice) {
-        $question->answer[$i] = addslashes(trim($choice->text));
-        if (in_array($choice->ident, $correct_answers)) {
-            // correct answer
-            $question->fraction[$i] = floor(100000/$correct_answer_count)/100000; // strange behavior if we have more than 5 decimal places
-            $question->feedback[$i] = $feedback->correct;
-        }
-        else {
-            // wrong answer 
-            $question->fraction[$i] = 0;
-            $question->feedback[$i] = $feedback->incorrect;
-        }
-        $i++;
-    }
-
-    $questions[] = $question;
-}
-
-//----------------------------------------
-// Process Essay Questions
-//----------------------------------------
-function process_essay($quest, &$questions) {
-// this should be rewritten to accomodate moodle 1.6 essay question type eventually
-    if (defined("ESSAY")) {
-        // treat as short answer
-        $question->qtype = ESSAY;
-        $question->defaultgrade = 1;
-        $question->usecase = 0; // Ignore case
-        $question->image = ""; // No images with this format
-        $question->questiontext = addslashes(trim($quest->QUESTION_BLOCK->text));
-        $question->name = $question->questiontext;
-    
-        print $question->name;
-    
-        $question->answer = array();
-        // not sure where to get the correct answer from
-        foreach($quest->feedback as $feedback) {
-        }
-        if (isset($question) && $question != '') {
-            $questions[]=$question;
-        }
-    }
-    else {
-        print "Essay question types are not handled because the quiz question type 'Essay' does not exist in this installation of Moodle<br/>";
-        print "&nbsp;&nbsp;&nbsp;&nbsp;Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';
-    }
-}
-
-//----------------------------------------
-// Process Matching Questions
-//----------------------------------------
-function process_matching($quest, &$questions) {
-    if (defined("RENDEREDMATCH")) {
-        $question = $this->defaultquestion($this->defaultquestion());
-        $question->valid = true;
-        $question->qtype = RENDEREDMATCH;
-        $question->defaultgrade = 1;
-        $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
-        $question->name = $question->questiontext;
-    
-        foreach($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {
-            foreach($quest->responses as $rid => $resp) {
-                if ($resp->ident == $subq->ident) {
-                    $correct = addslashes($resp->correct);
-                    $feedback = addslashes($resp->feedback);   
-                }
-            }
-        
-            foreach($subq->choices as $cid => $choice) {
-                if ($choice == $correct) {
-                    $question->subquestions[] = addslashes($subq->text);
-                    $question->subanswers[] = addslashes($quest->RIGHT_MATCH_BLOCK->matching_answerset[$cid]->text);
-                }
-            }
-        }
-    
-        // check format
-        $status = true;
-        if ( count($quest->RESPONSE_BLOCK->subquestions) > count($quest->RIGHT_MATCH_BLOCK->matching_answerset) || count($question->subquestions) < 2) {
-            $status = false;
-        }
-        else {
-            // need to redo to make sure that no two questions have the same answer (rudimentary now)
-            foreach($question->subanswers as $qstn) {
-                if(isset($previous)) {
-                    if ($qstn == $previous) {
-                        $status = false;   
-                    }                
-                }
-                $previous = $qstn;
-                if ($qstn == '') {
-                    $status = false;   
-                }
-            }
-        }
-    
-        if ($status) {
-            $questions[] = $question;   
-        }
-        else {
-            global $course, $CFG;
-            print '<table align="center" border="1">';
-            print '<tr><td colspan="2" style="background-color:#FF8888;">This matching question is malformed. Please ensure there are no blank answers, no two questions have the same answer, and/or there are correct answers for each question. There must be at least as many subanswers as subquestions, and at least one subquestion.</td></tr>'; 
-        
-            print "<tr><td>Question:</td><td>".$quest->QUESTION_BLOCK->text;
-            if (isset($quest->QUESTION_BLOCK->file)) {
-                print '<br/><font color="red">There is a subfile contained in the zipfile that has been copied to course files: bb_import/'.basename($quest->QUESTION_BLOCK->file).'</font>';
-                if (preg_match('/(gif|jpg|jpeg|png)$/i', $quest->QUESTION_BLOCK->file)) {
-                    print '<img src="'.$CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($quest->QUESTION_BLOCK->file).'" />';
-                }
-            }
-            print "</td></tr>";
-            print "<tr><td>Subquestions:</td><td><ul>";
-            foreach($quest->responses as $rs) {
-                $correct_responses->{$rs->ident} = $rs->correct;   
-            }
-            foreach($quest->RESPONSE_BLOCK->subquestions as $subq) {
-                print '<li>'.$subq->text.'<ul>';
-                foreach($subq->choices as $id=>$choice) {
-                    print '<li>';
-                    if ($choice == $correct_responses->{$subq->ident}) {
-                        print '<font color="green">';
-                    }
-                    else {
-                        print '<font color="red">';
-                    }
-                    print $quest->RIGHT_MATCH_BLOCK->matching_answerset[$id]->text.'</font></li>';
-                }
-                print '</ul>';
-            }
-            print '</ul></td></tr>';
-        
-            print '<tr><td>Feedback:</td><td><ul>';
-            foreach($quest->feedback as $fb) {
-                print '<li>'.$fb->ident.': '.$fb->text.'</li>';
-            }
-            print '</ul></td></tr></table>';
-        }
-    }
-    else {
-        print "Matching question types are not handled because the quiz question type 'Rendered Matching' does not exist in this installation of Moodle<br/>";
-        print "&nbsp;&nbsp;&nbsp;&nbsp;Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';
-    }
-}
-
-
-function strip_applet_tags_get_mathml($string) {
-    if(stristr($string, '</APPLET>') === FALSE) {
-        return $string;    
-    }
-    else {
-        // strip all applet tags keeping stuff before/after and inbetween (if mathml) them
-        while (stristr($string, '</APPLET>') !== FALSE) {
-            preg_match("/(.*)\<applet.*value=\"(\<math\>.*\<\/math\>)\".*\<\/applet\>(.*)/i",$string, $mathmls);
-            $string = $mathmls[1].$mathmls[2].$mathmls[3];
-        }
-        return $string;    
-    }
-}
-
-} // close object
-?>
+<?php\r
+\r
+////////////////////////////////////////////////////////////////////////////\r
+/// Blackboard 6.x Format\r
+///\r
+/// This Moodle class provides all functions necessary to import and export\r
+///\r
+///\r
+////////////////////////////////////////////////////////////////////////////\r
+\r
+// Based on default.php, included by ../import.php\r
+\r
+require_once ("$CFG->libdir/xmlize.php");\r
+\r
+class qformat_blackboard_6 extends qformat_default {\r
+    function provide_import() {\r
+        return true;\r
+    }\r
+    \r
+    \r
+    //Function to check and create the needed dir to unzip file to\r
+    function check_and_create_import_dir($unique_code) {\r
+\r
+        global $CFG; \r
+\r
+        $status = $this->check_dir_exists($CFG->dataroot."/temp",true);\r
+        if ($status) {\r
+            $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import",true);\r
+        }\r
+        if ($status) {\r
+            $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import/".$unique_code,true);\r
+        }\r
+        \r
+        return $status;\r
+    }\r
+    \r
+    function clean_temp_dir($dir='') {\r
+        // this needs to be reworked\r
+        \r
+        \r
+        // for now we will just say everything happened okay note that a mess may be piling up in $CFG->dataroot/temp/bbquiz_import\r
+        return true;\r
+        \r
+        if ($dir == '') {\r
+            $dir = $this->temp_dir;   \r
+        }\r
+        $slash = "/";\r
+\r
+        // Create arrays to store files and directories\r
+        $dir_files      = array();\r
+        $dir_subdirs    = array();\r
+\r
+        // Make sure we can delete it\r
+        chmod($dir, 0777);\r
+\r
+        if ((($handle = opendir($dir))) == FALSE) {\r
+            // The directory could not be opened\r
+            return false;\r
+        }\r
+\r
+        // Loop through all directory entries, and construct two temporary arrays containing files and sub directories\r
+        while($entry = readdir($handle)) {\r
+            if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != ".") {\r
+                $dir_subdirs[] = $dir. $slash .$entry;\r
+            }\r
+            else if ($entry != ".." && $entry != ".") {\r
+                $dir_files[] = $dir. $slash .$entry;\r
+            }\r
+        }\r
+\r
+        // Delete all files in the curent directory return false and halt if a file cannot be removed\r
+        for($i=0; $i<count($dir_files); $i++) {\r
+            chmod($dir_files[$i], 0777);\r
+            if (((unlink($dir_files[$i]))) == FALSE) {\r
+                return false;\r
+            }\r
+        }\r
+\r
+        // Empty sub directories and then remove the directory\r
+        for($i=0; $i<count($dir_subdirs); $i++) {\r
+            chmod($dir_subdirs[$i], 0777);\r
+            if ($this->clean_temp_dir($dir_subdirs[$i]) == FALSE) {\r
+                return false;\r
+            }\r
+            else {\r
+                if (rmdir($dir_subdirs[$i]) == FALSE) {\r
+                return false;\r
+                }\r
+            }\r
+        }\r
+\r
+        // Close directory\r
+        closedir($handle);\r
+        if (rmdir($this->temp_dir) == FALSE) {\r
+            return false;    \r
+        }\r
+        // Success, every thing is gone return true\r
+        return true;\r
+    }\r
+    \r
+    //Function to check if a directory exists and, optionally, create it\r
+    function check_dir_exists($dir,$create=false) {\r
+\r
+        global $CFG; \r
+\r
+        $status = true;\r
+        if(!is_dir($dir)) {\r
+            if (!$create) {\r
+                $status = false;\r
+            } else {\r
+                umask(0000);\r
+                $status = mkdir ($dir,$CFG->directorypermissions);\r
+            }\r
+        }\r
+        return $status;\r
+    }\r
+\r
+    function importpostprocess() {\r
+    /// Does any post-processing that may be desired\r
+    /// Argument is a simple array of question ids that \r
+    /// have just been added.\r
+    \r
+        // need to clean up temporary directory\r
+        return $this->clean_temp_dir();\r
+    }\r
+\r
+    function copy_file_to_course($filename) {\r
+        global $CFG;\r
+        global $course;\r
+        $filename = str_replace('\\','/',$filename);\r
+        $fullpath = $this->temp_dir.'/res00001/'.$filename;\r
+        $basename = basename($filename);\r
+    \r
+        $copy_to = $CFG->dataroot.'/'.$course->id.'/bb_import';\r
+        \r
+        if ($this->check_dir_exists($copy_to,true)) {\r
+            if(is_readable($fullpath)) {\r
+                $copy_to.= '/'.$basename;\r
+                if (!copy($fullpath, $copy_to)) {\r
+                    return false;\r
+                }\r
+                else {\r
+                    return $copy_to;\r
+                }\r
+            }\r
+        }\r
+        else {\r
+            return false;   \r
+        }\r
+    }\r
+\r
+    function readdata($filename) {\r
+    /// Returns complete file with an array, one item per line\r
+        global $CFG;\r
+        \r
+        $unique_code = time();\r
+        $temp_dir = $CFG->dataroot."/temp/bbquiz_import/".$unique_code;\r
+        $this->temp_dir = $temp_dir;\r
+        if ($this->check_and_create_import_dir($unique_code)) {\r
+            if(is_readable($filename)) {\r
+                if (!copy($filename, "$temp_dir/bboard.zip")) {\r
+                    error("Could not copy backup file");\r
+                }\r
+                if(unzip_file("$temp_dir/bboard.zip", '', false)) {\r
+                    // assuming that the information is in res0001.dat\r
+                    // after looking at 6 examples this was always the case\r
+                    $q_file = "$temp_dir/res00001.dat";\r
+                    if (is_file($q_file)) {\r
+                        if (is_readable($q_file)) {\r
+                            $filearray = file($q_file);\r
+                            /// Check for Macintosh OS line returns (ie file on one line), and fix\r
+                            if (ereg("\r", $filearray[0]) AND !ereg("\n", $filearray[0])) {\r
+                                return explode("\r", $filearray[0]);\r
+                            } else {\r
+                                return $filearray;\r
+                            }\r
+                            return false;        \r
+                        }\r
+                    }\r
+                    else {\r
+                        error("Could not find question data file in zip");   \r
+                    }\r
+                }\r
+                else {\r
+                    print "filename: $filename<br />tempdir: $temp_dir <br />";\r
+                    error("Could not unzip file.");   \r
+                }\r
+            }\r
+            else {\r
+                error ("Could not read uploaded file");   \r
+            }\r
+        }\r
+        else {\r
+            error("Could not create temporary directory");   \r
+        }\r
+    }\r
+        \r
+    function save_question_options($question) {\r
+        return true; \r
+    }\r
+    \r
+    \r
+    \r
+  function readquestions ($lines) {\r
+    /// Parses an array of lines into an array of questions,\r
+    /// where each item is a question object as defined by\r
+    /// readquestion(). \r
+\r
+    $text = implode($lines, " ");\r
+    $xml = xmlize($text, 0);\r
+\r
+    $raw_questions = $xml['questestinterop']['#']['assessment'][0]['#']['section'][0]['#']['item'];\r
+       //echo "Line 213: Raw Questions <br>";\r
+       //print_object($raw_questions);\r
+    $questions = array();\r
+\r
+    foreach($raw_questions as $quest) {\r
+        $question = $this->create_raw_question($quest);\r
+               \r
+               switch($question->qtype) {\r
+            case "Matching":\r
+                $this->process_matching($question, $questions);\r
+                break;\r
+            case "Multiple Choice":\r
+                $this->process_mc($question, $questions);\r
+                break;\r
+            case "Essay":\r
+                $this->process_essay($question, $questions);\r
+                break;\r
+            case "Multiple Answer":\r
+                $this->process_ma($question, $questions);\r
+                break;\r
+            case "True/False":\r
+                $this->process_tf($question, $questions);\r
+                break;\r
+            case 'Fill in the Blank':\r
+                $this->process_fblank($question, $questions);\r
+                break;\r
+            default:\r
+                print "Unknown or unhandled question type: \"$question->qtype\"<br />";\r
+                break;\r
+        }\r
+\r
+    }\r
+    //echo "readquestions:";\r
+       //print_object ($questions);\r
+    return $questions;\r
+  }\r
+\r
+\r
+// creates a cleaner object to deal with for processing into moodle\r
+// the object created is NOT a moodle question object\r
+function create_raw_question($quest) {\r
+    \r
+       $question = $this->defaultquestion();\r
+    $question->qtype = $quest['#']['itemmetadata'][0]['#']['bbmd_questiontype'][0]['#'];\r
+    $presentation->blocks = $quest['#']['presentation'][0]['#']['flow'][0]['#']['flow'];\r
+       \r
+       foreach($presentation->blocks as $pblock) {\r
+        \r
+        $block = NULL;\r
+        $block->type = $pblock['@']['class'];\r
+               \r
+        switch($block->type) {\r
+            case 'QUESTION_BLOCK':\r
+                $sub_blocks = $pblock['#']['flow'];\r
+                foreach($sub_blocks as $sblock) {\r
+                                       //echo "Calling process_block from line 263<br>";\r
+                    $this->process_block($sblock, $block);  \r
+                }\r
+                break;\r
+                               \r
+            case 'RESPONSE_BLOCK':\r
+                $choices = NULL;\r
+                switch($question->qtype) {\r
+                    case 'Matching':\r
+                        $bb_subquestions = $pblock['#']['flow'];\r
+                        $sub_questions = array();\r
+                        foreach($bb_subquestions as $bb_subquestion) {\r
+                                                       $sub_question = NULL;\r
+                            $sub_question->ident = $bb_subquestion['#']['response_lid'][0]['@']['ident'];\r
+                                                       //echo "Calling process_block from line 277<br>";\r
+                            $this->process_block($bb_subquestion['#']['flow'][0], $sub_question);\r
+                            $bb_choices = $bb_subquestion['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];\r
+                            $choices = array();\r
+                            $this->process_choices($bb_choices, $choices);\r
+                            $sub_question->choices = $choices;\r
+                            if (!isset($block->subquestions)) {\r
+                                $block->subquestions = array();\r
+                            }\r
+                            $block->subquestions[] = $sub_question;\r
+                        }\r
+                        break;\r
+                    case 'Multiple Answer':\r
+                        $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];\r
+                        $choices = array();\r
+                        $this->process_choices($bb_choices, $choices);\r
+                                               $block->choices = $choices;\r
+                                               \r
+                                               break;\r
+                    case 'Essay':\r
+                        // Doesn't apply since the user responds with text input\r
+                        break;\r
+                    case 'Multiple Choice':\r
+                        $mc_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];\r
+                        \r
+                                               foreach($mc_choices as $mc_choice) {\r
+                            $choices = NULL;\r
+                                                       \r
+                                                       \r
+                                                       \r
+                                                       //echo "Calling process_block from line 307<br>";\r
+                                                       $choices = $this->process_block($mc_choice, $choices);\r
+                                                       $block->choices[] = $choices;             \r
+                        }\r
+                        break;\r
+                    case 'Fill in the Blank':\r
+                        // do nothing?\r
+                        break;\r
+                    default:\r
+                        $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];\r
+                        $choices = array();\r
+                        $this->process_choices($bb_choices, $choices);\r
+                        $block->choices = $choices;\r
+                }\r
+                break;\r
+            case 'RIGHT_MATCH_BLOCK':\r
+                $matching_answerset = $pblock['#']['flow'];\r
+                $answerset = array();\r
+                foreach($matching_answerset as $answer) {\r
+                                       //echo "Calling process_block from line 235<br>";\r
+                    $this->process_block($answer, $bb_answer);\r
+                    $answerset[] = $bb_answer;\r
+                }\r
+                $block->matching_answerset = $answerset;\r
+                break;\r
+            default:\r
+                print "UNHANDLED PRESENTATION BLOCK";\r
+                break;\r
+        }\r
+        $question->{$block->type} = $block;\r
+    }\r
+    \r
+    // determine response processing \r
+    // there is a section called 'outcomes' that I don't know what to do with\r
+    $resprocessing = $quest['#']['resprocessing'];\r
+       \r
+       $respconditions = $resprocessing[0]['#']['respcondition'];\r
+       //echo "Line 347: respconditions<br>";\r
+       //print_object ($respconditions);\r
+       \r
+       $reponses = array();\r
+    if ($question->qtype == 'Matching') {\r
+        $this->process_matching_responses($respconditions, $responses);\r
+    }\r
+    else {\r
+        $this->process_responses($respconditions, $responses);\r
+    }\r
+    $question->responses = $responses;\r
+       \r
+    $feedbackset = $quest['#']['itemfeedback'];\r
+       \r
+       $feedbacks = array();\r
+       \r
+       //echo "Line 362: Calling Process Feedback:<br>";\r
+       $this->process_feedback($feedbackset, $feedbacks);\r
+    $question->feedback = $feedbacks;\r
+               \r
+       //echo "Line 358: ";\r
+       //print_object($question);\r
+    return $question;\r
+}\r
+\r
+function process_block($cur_block, &$block) {\r
+       \r
+    $cur_type = $cur_block['@']['class'];\r
+               \r
+       global $course, $CFG;\r
+    switch($cur_type) {\r
+        case 'FORMATTED_TEXT_BLOCK':\r
+            $block->text = $this->strip_applet_tags_get_mathml($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']); \r
+                       //echo "Line 378: " . $block->text . '<br>';\r
+                       break;\r
+        case 'FILE_BLOCK':\r
+            //revisit this to make sure it is working correctly\r
+                       \r
+                       // Commented out ['matapplication']..., etc. because I noticed that when I imported a new Blackboard 6 file\r
+                       // and printed out the block, the tree did not extend past ['material'][0]['#'] - CT 8/3/06\r
+            $block->file = $cur_block['#']['material'][0]['#'];//['matapplication'][0]['@']['uri'];\r
+            if ($block->file != '') {\r
+                // if we have a file copy it to the course dir and adjust its name to be visible over the web.\r
+                $block->file = $this->copy_file_to_course($block->file);\r
+                $block->file = $CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($block->file);\r
+            }\r
+            break;\r
+        case 'Block':\r
+                       \r
+                       if (isset($cur_block['#']['material'][0]['#']['mattext'][0]['#'])) {\r
+                       $block->text = $cur_block['#']['material'][0]['#']['mattext'][0]['#'];\r
+                               \r
+                                //echo "line 379 - isset:" . isset($block->text);\r
+                                //echo "Type: " . $cur_type . " Is Object:" . is_object($block) . "<br>\r\n";\r
+            }\r
+            else if (isset($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'])) {\r
+                $block->text = $cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'];\r
+            }\r
+            else if (isset($cur_block['#']['response_label'])) {\r
+                // this is a response label block\r
+                $sub_blocks = $cur_block['#']['response_label'][0];\r
+                if(!isset($block->ident)) {\r
+                    if(isset($sub_blocks['@']['ident'])) {\r
+                        $block->ident = $sub_blocks['@']['ident'];\r
+                                               //echo "Line 409: <br>";\r
+                                               //print_object($cur_block);\r
+                    }\r
+                }\r
+                foreach($sub_blocks['#']['flow_mat'] as $sub_block) {\\r
+                                       //echo "Calling process_block from line 404<br>";\r
+                                       //$block = null;                        // Reset $block to NULL because process_block is expecting an object\r
+                                                                                               // for the second argument and not a string, which is what is was set as\r
+                                                                                               // originally\r
+                                       \r
+                    $this->process_block($sub_block, $block);   \r
+                }\r
+            }\r
+            else {\r
+                if (isset($cur_block['#']['flow_mat']) || isset($cur_block['#']['flow'])) {\r
+                    if (isset($cur_block['#']['flow_mat'])) {\r
+                        $sub_blocks = $cur_block['#']['flow_mat'];\r
+                    }\r
+                    elseif (isset($cur_block['#']['flow'])) {\r
+                        $sub_blocks = $cur_block['#']['flow'];\r
+                    }\r
+                   foreach ($sub_blocks as $sblock) {\r
+                        // this will recursively grab the sub blocks which should be of one of the other types\r
+                                               //echo "Calling process_block from line 419<br>";\r
+                        $this->process_block($sblock, $block);\r
+                    }\r
+                }\r
+            }\r
+            break;\r
+        case 'LINK_BLOCK':\r
+            // not sure how this should be included\r
+            if (!empty($cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'])) {\r
+                $block->link = $cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'];\r
+            }\r
+            else {\r
+               $block->link = '';\r
+            }\r
+            break;    \r
+    }    \r
+       //echo "Line 446: " . $block->text . '<br>';\r
+       return $block;\r
+}\r
+\r
+function process_choices($bb_choices, &$choices) {\r
+       \r
+       foreach($bb_choices as $choice) {\r
+               if (isset($choice['@']['ident'])) {\r
+            $cur_choice = $choice['@']['ident'];\r
+        }\r
+        else {         //for multiple answer\r
+            $cur_choice = $choice['#']['response_label'][0];//['@']['ident'];\r
+                       //echo "['#']['response_label'][0]['@']['ident']<br>\r\n";\r
+        }\r
+        if (isset($choice['#']['flow_mat'][0])) {      //for multiple answer\r
+            $cur_block = $choice['#']['flow_mat'][0];\r
+                       $cur_choice = null;             // Reset $cur_choice to NULL because process_block is expecting an object\r
+                                                                       // for the second argument and not a string, which is what is was set as\r
+                                                                       // originally - CT 8/7/06\r
+                       //echo "Calling process_block from line 448<br>";\r
+                       $this->process_block($cur_block, $cur_choice);\r
+        }\r
+        elseif (isset($choice['#']['response_label'])) {\r
+                       $cur_choice = null;             // Reset $cur_choice to NULL because process_block is expecting an object\r
+                                                                       // for the second argument and not a string, which is what is was set as\r
+                                                                       // originally - CT 8/7/06\r
+                       //echo "Calling process_block from line 452<br>";\r
+            $this->process_block($choice, $cur_choice);\r
+        }\r
+        $choices[] = $cur_choice;\r
+    }    \r
+}\r
+\r
+function process_matching_responses($bb_responses, &$responses) {\r
+       //echo "Line 486: Matching!<br>";\r
+    //print_object($bb_responses);\r
+    foreach($bb_responses as $bb_response) {\r
+        $response = NULL;\r
+        if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'])) {\r
+            $response->correct = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#'];\r
+            $response->ident = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['@']['respident'];\r
+        }\r
+        else {\r
+            $response->correct =  'Broken Question?';\r
+            $response->ident = 'Broken Question?';\r
+        }\r
+        $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];\r
+        $responses[] = $response;\r
+    }\r
+}\r
+\r
+function process_responses($bb_responses, &$responses) {\r
+               \r
+               foreach($bb_responses as $bb_response) {\r
+                       $response = null;               //Added this line to instantiate $response.\r
+                                                                       // Without instantiating the $response variable, the same object\r
+                                                                       // gets added to the array\r
+                       //echo "Line 504: bb_response<br>";\r
+                       //print_object ($bb_response);\r
+                       \r
+                       if (isset($bb_response['@']['title'])) {\r
+                $response->title = $bb_response['@']['title'];    \r
+            }\r
+            else {\r
+                $reponse->title = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];\r
+            }\r
+            $reponse->ident = array();\r
+            if (isset($bb_response['#']['conditionvar'][0]['#'])){//['varequal'][0]['#'])) {\r
+                $response->ident[0] = $bb_response['#']['conditionvar'][0]['#'];//['varequal'][0]['#'];    \r
+            }\r
+            else if (isset($bb_response['#']['conditionvar'][0]['#']['other'][0]['#'])) {\r
+                $response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['other'][0]['#'];  \r
+            }\r
+            \r
+            if (isset($bb_response['#']['conditionvar'][0]['#']['and'])){//[0]['#'])) {\r
+                $responseset = $bb_response['#']['conditionvar'][0]['#']['and'];//[0]['#']['varequal'];\r
+                foreach($responseset as $rs) {\r
+                    $response->ident[] = $rs['#'];\r
+                    if(!isset($response->feedback) and isset( $rs['@'] ) ) {\r
+                        $response->feedback = $rs['@']['respident'];\r
+                    }    \r
+                }\r
+            }\r
+            else {\r
+                $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];   \r
+            }\r
+\r
+            // determine what point value to give response\r
+            if (isset($bb_response['#']['setvar'])) {\r
+                switch ($bb_response['#']['setvar'][0]['#']) {\r
+                    case "SCORE.max":\r
+                        $response->fraction = 1;\r
+                        break;\r
+                    default:\r
+                        // I have only seen this being 0 or unset  there are probably fractional values of SCORE.max, but I'm not sure what they look like\r
+                        $response->fraction = 0;\r
+                        break;\r
+                }\r
+            }\r
+            else {\r
+               // just going to assume this is the case this is probably not correct.\r
+               $response->fraction = 0;\r
+            }\r
+            \r
+                       \r
+               \r
+            $responses[] = $response;\r
+                       //echo "Line 554: $responses<br>";\r
+                       //print_object ($responses);\r
+        }\r
+}\r
+\r
+function process_feedback($feedbackset, &$feedbacks) {\r
+       //echo "Line 551: In Process Feedback<br>";\r
+       //echo "Line 552: feedbacks<br>";\r
+       //print_object($feedbacks);\r
+    foreach($feedbackset as $bb_feedback) {\r
+               $feedback = null;  // Added line $feedback=null so that $feedback does not get reused in the loop\r
+                                                  // and added the the $feedbacks[] array multiple times\r
+               $feedback->ident = $bb_feedback['@']['ident'];\r
+               //echo "Line 558: " . $feedback->ident . "<br>\r\n";\r
+        if (isset($bb_feedback['#']['flow_mat'][0])) {\r
+                       //echo "Calling process_block from line 531<br>";\r
+            $this->process_block($bb_feedback['#']['flow_mat'][0], $feedback);\r
+                       \r
+        }\r
+        elseif (isset($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0])) {\r
+                       //echo "Calling process_block from line 535<br>";\r
+            $this->process_block($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0], $feedback);\r
+        }\r
+        $feedbacks[] = $feedback;\r
+               \r
+               //echo "Line 568: feedbacks<br>";\r
+               //print_object($feedbacks);\r
+    }\r
+       //echo "Line 571: feedbacks<br>";\r
+       //print_object($feedbacks);\r
+       \r
+}\r
+\r
+//----------------------------------------\r
+// Process True / False Questions\r
+//----------------------------------------\r
+function process_tf($quest, &$questions) {\r
+    $question = $this->defaultquestion();\r
+\r
+    $question->qtype = TRUEFALSE;\r
+    $question->defaultgrade = 1;\r
+    $question->single = 1;     // Only one answer is allowed\r
+    $question->image = "";     // No images with this format\r
+       $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
+    // put name in question object\r
+    $question->name = $question->questiontext;\r
+\r
+    // first choice is true, second is false.\r
+    if ($quest->responses[0]->fraction == 1) {\r
+        $correct = true;    \r
+    }\r
+    else {\r
+        $correct = false;   \r
+    }\r
+    \r
+    foreach($quest->feedback as $fb) {\r
+        $fback->{$fb->ident} = $fb->text;   \r
+    }\r
+    \r
+    if ($correct) {  // true is correct\r
+        $question->answer = 1;\r
+        $question->feedbacktrue = addslashes($fback->correct);\r
+        $question->feedbackfalse = addslashes($fback->incorrect);\r
+    } else {  // false is correct\r
+        $question->answer = 0;\r
+        $question->feedbacktrue = addslashes($fback->incorrect);\r
+        $question->feedbackfalse = addslashes($fback->correct);\r
+    }\r
+    $questions[] = $question;\r
+}\r
+\r
+\r
+//----------------------------------------\r
+// Process Fill in the Blank\r
+//----------------------------------------\r
+function process_fblank($quest, &$questions) {\r
+    \r
+       //echo "Line 633: Quest<br>";\r
+       //print_object($quest);\r
+       \r
+       $question = $this->defaultquestion();\r
+    $question->qtype = SHORTANSWER;\r
+    $question->defaultgrade = 1;\r
+    $question->single = 1;\r
+    $question->usecase = 0;\r
+    $question->image = '';\r
+    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
+    $question->name = $question->questiontext;\r
+    $answers = array();\r
+    $fractions = array();\r
+    $feedbacks = array();\r
+    \r
+    // extract the feedback\r
+    $feedback = array();\r
+    foreach($quest->feedback as $fback) {\r
+        if (isset($fback->ident)) {\r
+            if ($fback->ident == 'correct' || $fback->ident == 'incorrect')\r
+                       {\r
+                               $feedback[$fback->ident] = $fback->text;\r
+                       }\r
+        }\r
+    }\r
+    \r
+    foreach($quest->responses as $response) {\r
+        if(isset($response->title)) {\r
+               \r
+                   if (isset($response->ident[0]['varequal'][0]['#']))\r
+                       {\r
+                               //for BB Fill in the Blank, only interested in correct answers\r
+                               if ($response->feedback = 'correct')\r
+                               {\r
+                                       $answers[] = addslashes($response->ident[0]['varequal'][0]['#']);\r
+                                       $fractions[] = 1;\r
+                                        if (isset($feedback['correct'])) \r
+                                        {\r
+                                       $feedbacks[] = addslashes($feedback['correct']);\r
+                                    }\r
+                                        else\r
+                                       {\r
+                                               $feedbacks[] = '';\r
+                                       }\r
+                               }\r
+                       }\r
+  \r
+        }\r
+    }\r
+       \r
+       //Adding catchall to so that students can see feedback for incorrect answers when they enter something the \r
+       //instructor did not enter\r
+       \r
+       $answers[] = '*';\r
+       $fractions[] = 0;\r
+       if (isset($feedback['incorrect'])) \r
+       {\r
+               $feedbacks[] = addslashes($feedback['incorrect']);\r
+       }\r
+       else\r
+       {\r
+               $feedbacks[] = '';\r
+       }\r
+    \r
+    $question->answer = $answers;\r
+    $question->fraction = $fractions;\r
+       $question->feedback = $feedbacks;                               // Changed to assign $feedbacks to $question->feedback instead of\r
+                                                                                                       // $feedback - CT 8/10/06\r
+//    $question->feedback = $feedback;\r
+\r
+    if (!empty($question)) {\r
+        $questions[] = $question;\r
+    }\r
+\r
+}\r
+\r
+//----------------------------------------\r
+// Process Multiple Choice Questions\r
+//----------------------------------------\r
+function process_mc($quest, &$questions) {\r
+       //echo "Line 667: Quest<br>";\r
+       //print_object($quest);\r
+       \r
+       $question = $this->defaultquestion();\r
+    $question->qtype = MULTICHOICE;\r
+    $question->defaultgrade = 1;\r
+    $question->single = 1;\r
+    $question->image = "";\r
+    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
+    $question->name = $question->questiontext;\r
+    \r
+    $feedback = array();\r
+    foreach($quest->feedback as $fback) {\r
+        $feedback[$fback->ident] = addslashes($fback->text);\r
+    }\r
+       \r
+       //echo "Line 683: feedback<br>";\r
+       //print_object($feedback);\r
\r
+    foreach($quest->responses as $response) {\r
+       \r
+        if (isset($response->title)) {\r
+            if ($response->title == 'correct') {\r
+                // only one answer possible for this qtype so first index is correct answer\r
+                $correct = $response->ident[0]['varequal'][0]['#'];    // added [0]['varequal'][0]['#'] to $response->ident - CT 8/9/06\r
+            }\r
+        }\r
+        else {\r
+            // fallback method for when the title is not set\r
+            if ($response->feedback == 'correct') {\r
+               // only one answer possible for this qtype so first index is correct answer\r
+               $correct = $response->ident[0]['varequal'][0]['#']; // added [0]['varequal'][0]['#'] to $response->ident - CT 8/9/06\r
+            }\r
+        }\r
+    }\r
+       \r
+       //echo "Line 706: Correct:" . $correct . "<br>";\r
+\r
+    $i = 0;\r
+    foreach($quest->RESPONSE_BLOCK->choices as $response) {\r
+               \r
+               $question->answer[$i] = addslashes($response->text);\r
+        if ($correct == $response->ident) {\r
+            $question->fraction[$i] = 1;\r
+            // this is a bit of a hack to catch the feedback... first we see if a 'correct' feedback exists\r
+            // then specific feedback for this question (maybe this should be switched?, but from my example\r
+            // question pools I have not seen response specific feedback, only correct or incorrect feedback\r
+            if (!empty($feedback['correct'])) {\r
+                $question->feedback[$i] = $feedback['correct'];\r
+            }\r
+            elseif (!empty($feedback[$i])) {\r
+                $question->feedback[$i] = $feedback[$i];\r
+            }\r
+            else {\r
+                // failsafe feedback (should be '' instead?)\r
+                $question->feedback[$i] = "correct";   \r
+            }\r
+        }    \r
+        else {\r
+            $question->fraction[$i] = 0;\r
+            if (!empty($feedback['incorrect'])) {\r
+                $question->feedback[$i] = $feedback['incorrect'];\r
+            }\r
+            elseif (!empty($feedback[$i])) {\r
+                $question->feedback[$i] = $feedback[$i];\r
+            }\r
+            else {\r
+                // failsafe feedback (should be '' instead?)\r
+                $question->feedback[$i] = 'incorrect';\r
+            }\r
+        }\r
+        $i++;\r
+    }\r
+\r
+    if (!empty($question)) {\r
+        $questions[] = $question;\r
+    }\r
+}\r
+\r
+//----------------------------------------\r
+// Process Multiple Choice Questions With Multiple Answers\r
+//----------------------------------------\r
+function process_ma($quest, &$questions) {\r
+\r
+       //echo "Line 763: Quest<br>";\r
+       //print_object($quest);\r
+       \r
+       $question = $this->defaultquestion();   // copied this from process_mc\r
+                                                                                       // noticed it was missing - CT 8/8/06\r
+    $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
+    $question->name = $question->questiontext; \r
+    $question->qtype = MULTICHOICE;\r
+    $question->defaultgrade = 1;\r
+    $question->single = 0;     // More than one answer allowed\r
+    $question->image = "";     // No images with this format\r
+\r
+    $answers = $quest->responses;\r
+    $correct_answers = array();\r
+    foreach($answers as $answer) {\r
+       \r
+       //echo 'Line 779: $answer<br>';\r
+       //print_object($answer);\r
+        if($answer->title == 'correct') {\r
+            $answerset = $answer->ident[0]['and'][0]['#']['varequal'];  // added [0]['and'][0]['#']['varequal'] to $answer->ident - CT 8/9/06\r
+            foreach($answerset as $ans) {\r
+                $correct_answers[] = $ans['#'];                                                        // added ['#'] to $ans - CT 8/9/06\r
+            }\r
+        }\r
+    }\r
+    \r
+    foreach ($quest->feedback as $fb) {\r
+        $feedback->{$fb->ident} = addslashes(trim($fb->text));\r
+    }\r
+    \r
+    $correct_answer_count = count($correct_answers);\r
+    $choiceset = $quest->RESPONSE_BLOCK->choices;\r
+    $i = 0;\r
+    foreach($choiceset as $choice) {\r
+        $question->answer[$i] = addslashes(trim($choice->text));\r
+        if (in_array($choice->ident, $correct_answers)) {\r
+            // correct answer\r
+            $question->fraction[$i] = floor(100000/$correct_answer_count)/100000; // strange behavior if we have more than 5 decimal places\r
+            $question->feedback[$i] = $feedback->correct;\r
+        }\r
+        else {\r
+            // wrong answer \r
+            $question->fraction[$i] = 0;\r
+            $question->feedback[$i] = $feedback->incorrect;\r
+        }\r
+        $i++;\r
+    }\r
+\r
+    $questions[] = $question;\r
+       //echo "Line 807: question<br>";\r
+       //print_object($question);\r
+}\r
+\r
+//----------------------------------------\r
+// Process Essay Questions\r
+//----------------------------------------\r
+function process_essay($quest, &$questions) {\r
+// this should be rewritten to accomodate moodle 1.6 essay question type eventually\r
+\r
+       //echo "Line 822: Quest<br>";\r
+       //print_object($quest);\r
+       \r
+    if (defined("ESSAY")) {\r
+        // treat as short answer\r
+               \r
+               $question = $this->defaultquestion();   // copied this from process_mc\r
+                                                                                       // noticed it was missing - CT 8/8/06\r
+        $question->qtype = ESSAY;\r
+        $question->defaultgrade = 1;\r
+        $question->usecase = 0;        // Ignore case\r
+        $question->image = ""; // No images with this format\r
+        $question->questiontext = addslashes(trim($quest->QUESTION_BLOCK->text));\r
+        $question->name = $question->questiontext;\r
+    \r
+        print $question->name;\r
+    \r
+        $question->feedback = array();\r
+        // not sure where to get the correct answer from\r
+        foreach($quest->feedback as $feedback) {\r
+                       \r
+                       // Added this code to put the possible solution that the instructor gives as the Moodle answer for an essay question\r
+                       // - CT 8/9/06\r
+                       if ($feedback->ident == 'solution') \r
+                       {       \r
+                               $question->feedback = $feedback->text;\r
+                       }\r
+                       \r
+               \r
+        }\r
+               \r
+               $question->fraction[] = 1;              //Added because essay/questiontype.php:save_question_option is expecting a \r
+                                                                               //fraction property - CT 8/10/06\r
+        if (!empty($question)) {\r
+            $questions[]=$question;\r
+        }\r
+               \r
+               \r
+    }\r
+    else {\r
+        print "Essay question types are not handled because the quiz question type 'Essay' does not exist in this installation of Moodle<br/>";\r
+        print "&nbsp;&nbsp;&nbsp;&nbsp;Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';\r
+    }\r
+}\r
+\r
+//----------------------------------------\r
+// Process Matching Questions\r
+//----------------------------------------\r
+function process_matching($quest, &$questions) {\r
+\r
+       //echo "Line 910: Quest<br>";\r
+       //print_object($quest);\r
+       \r
+    if (defined("RENDEREDMATCH")) {\r
+        $question = $this->defaultquestion($this->defaultquestion());\r
+        $question->valid = true;\r
+        $question->qtype = RENDEREDMATCH;\r
+        $question->defaultgrade = 1;\r
+        $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
+        $question->name = $question->questiontext;\r
+    \r
+        foreach($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {\r
+            foreach($quest->responses as $rid => $resp) {\r
+                if ($resp->ident == $subq->ident) {\r
+                    $correct = addslashes($resp->correct);\r
+                    $feedback = addslashes($resp->feedback);   \r
+                }\r
+            }\r
+        \r
+            foreach($subq->choices as $cid => $choice) {\r
+                if ($choice == $correct) {\r
+                    $question->subquestions[] = addslashes($subq->text);\r
+                    $question->subanswers[] = addslashes($quest->RIGHT_MATCH_BLOCK->matching_answerset[$cid]->text);\r
+                }\r
+            }\r
+        }\r
+    \r
+        // check format\r
+        $status = true;\r
+        if ( count($quest->RESPONSE_BLOCK->subquestions) > count($quest->RIGHT_MATCH_BLOCK->matching_answerset) || count($question->subquestions) < 2) {\r
+            $status = false;\r
+        }\r
+        else {\r
+            // need to redo to make sure that no two questions have the same answer (rudimentary now)\r
+            foreach($question->subanswers as $qstn) {\r
+                if(isset($previous)) {\r
+                    if ($qstn == $previous) {\r
+                        $status = false;   \r
+                    }                \r
+                }\r
+                $previous = $qstn;\r
+                if ($qstn == '') {\r
+                    $status = false;   \r
+                }\r
+            }\r
+        }\r
+    \r
+        if ($status) {\r
+            $questions[] = $question;   \r
+        }\r
+        else {\r
+            global $course, $CFG;\r
+            print '<table align="center" border="1">';\r
+            print '<tr><td colspan="2" style="background-color:#FF8888;">This matching question is malformed. Please ensure there are no blank answers, no two questions have the same answer, and/or there are correct answers for each question. There must be at least as many subanswers as subquestions, and at least one subquestion.</td></tr>'; \r
+        \r
+            print "<tr><td>Question:</td><td>".$quest->QUESTION_BLOCK->text;\r
+            if (isset($quest->QUESTION_BLOCK->file)) {\r
+                print '<br/><font color="red">There is a subfile contained in the zipfile that has been copied to course files: bb_import/'.basename($quest->QUESTION_BLOCK->file).'</font>';\r
+                if (preg_match('/(gif|jpg|jpeg|png)$/i', $quest->QUESTION_BLOCK->file)) {\r
+                    print '<img src="'.$CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($quest->QUESTION_BLOCK->file).'" />';\r
+                }\r
+            }\r
+            print "</td></tr>";\r
+            print "<tr><td>Subquestions:</td><td><ul>";\r
+            foreach($quest->responses as $rs) {\r
+                $correct_responses->{$rs->ident} = $rs->correct;   \r
+            }\r
+            foreach($quest->RESPONSE_BLOCK->subquestions as $subq) {\r
+                print '<li>'.$subq->text.'<ul>';\r
+                foreach($subq->choices as $id=>$choice) {\r
+                    print '<li>';\r
+                    if ($choice == $correct_responses->{$subq->ident}) {\r
+                        print '<font color="green">';\r
+                    }\r
+                    else {\r
+                        print '<font color="red">';\r
+                    }\r
+                    print $quest->RIGHT_MATCH_BLOCK->matching_answerset[$id]->text.'</font></li>';\r
+                }\r
+                print '</ul>';\r
+            }\r
+            print '</ul></td></tr>';\r
+        \r
+            print '<tr><td>Feedback:</td><td><ul>';\r
+            foreach($quest->feedback as $fb) {\r
+                print '<li>'.$fb->ident.': '.$fb->text.'</li>';\r
+            }\r
+            print '</ul></td></tr></table>';\r
+        }\r
+    }\r
+    else {\r
+        print "Matching question types are not handled because the quiz question type 'Rendered Matching' does not exist in this installation of Moodle<br/>";\r
+        print "&nbsp;&nbsp;&nbsp;&nbsp;Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';\r
+    }\r
+}\r
+\r
+\r
+function strip_applet_tags_get_mathml($string) {\r
+    if(stristr($string, '</APPLET>') === FALSE) {\r
+        return $string;    \r
+    }\r
+    else {\r
+        // strip all applet tags keeping stuff before/after and inbetween (if mathml) them\r
+        while (stristr($string, '</APPLET>') !== FALSE) {\r
+            preg_match("/(.*)\<applet.*value=\"(\<math\>.*\<\/math\>)\".*\<\/applet\>(.*)/i",$string, $mathmls);\r
+            $string = $mathmls[1].$mathmls[2].$mathmls[3];\r
+        }\r
+        return $string;    \r
+    }\r
+}\r
+\r
+} // close object\r
+?>\r