From: pkiddie <pk...@us...> - 2005-10-05 11:43:57
|
Update of /cvsroot/stack/stack-1-0/scripts/rqp/moodle_16_rqp/quiz/questiontypes/rqp In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4725/scripts/rqp/moodle_16_rqp/quiz/questiontypes/rqp Modified Files: editquestion.php lib.php options.php questiontype.php types.php Log Message: Latest version of RQPServer and client Implemented options Error reporting Index: lib.php =================================================================== RCS file: /cvsroot/stack/stack-1-0/scripts/rqp/moodle_16_rqp/quiz/questiontypes/rqp/lib.php,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** lib.php 12 Sep 2005 09:46:59 -0000 1.1 --- lib.php 5 Oct 2005 11:43:44 -0000 1.2 *************** *** 22,25 **** --- 22,28 ---- define ('RQP_VER','1.0'); + //This global array holds an ordered, up to date list of all RQP types + $rqpTypes = array(); + /** * Checks the current version of PHP and uses the correct instance checking function, based *************** *** 50,65 **** } /** ! * Create an option dialog and pass $optionType and $type to options.php script by GET method */ ! function quiz_rqp_optionsDialog($optionType, $type) { $jsOpenOptions = '<script language="javascript" type="text/javascript">'; ! $jsOpenOptions .= 'javascript:'; ! $jsOpenOptions .= "window.open('options.php?typeid=$type&optionstype=$optionType','optionspopup', ! 'left=20,top=20,width=500,height=500,toolbar=0,resizable=1')"; $jsOpenOptions .= '</script>'; echo $jsOpenOptions; } --- 53,145 ---- } + //For a specified type, retrieve the administrators options + function quiz_rqp_get_admin_options($typeid) { + + if (!$adminOptions = get_record('quiz_rqp_types', 'id', $typeid)) { + return false; + } + + else return $adminOptions->options; + } + + //For a specified user and RQP server type, retrieve the user options + function quiz_rqp_get_user_options($userid, $typeid) { + if (!$userOptions = get_record('quiz_rqp_user_options', 'userid', $userid, 'typeid', $typeid)) { + return false; + } + + else return $userOptions->options; + } + + //For a specified quiz and RQP server type, retrieve the quiz options (part of the teacher options) + function quiz_rqp_get_quiz_options($quizid, $typeid) { + if (!$quizOptions = get_record('quiz_rqp_quiz_options', 'quizid', $quizid, 'typeid', $typeid)) { + return false; + } + + else return $quizOptions->options; + } + + //For a specified course and RQP server type, retrieve the course options (part of the teacher options) + function quiz_rqp_get_course_options($courseid, $typeid) { + if (!$courseOptions = get_record('quiz_rqp_course_options', 'courseid', $courseid, 'typeid', $typeid)) { + return false; + } + + else return $courseOptions->options; + } + + //For a specified course, quiz and RQP server type, retrieve the teachers options (quiz options, if they exist + //override the course options + //TODO: Some options manipulation here, as course options and quiz options under umbrella of 'teacher' options. + //These options strings are RQP server specific, in STACK's case each option represented in as a value in an array + //So this is the functionality atm + function quiz_rqp_get_teacher_options($quizid, $courseid, $typeid) { + + //1. Get quiz options and use as teacherOptions if they exist + if (!$teacherOptions = quiz_rqp_get_quiz_options($quizid,$typeid)) { + //1.1 Unsuccessful, so use course options, if they exist + $teacherOptions = quiz_rqp_get_course_options($courseid, $typeid); + } + + return $teacherOptions; //false if no quiz/course options found for RQP type + //otherwise serialsied options string + } + /** ! * Create an option dialog and pass required parameters to the options.php script by GET method ! * optionType can be one of userOptions, teacherOptions, adminOptions */ ! function quiz_rqp_optionsDialog($optionType, $type="", $course="", $user="", $quiz="") { + global $CFG; + + //Echo javascript to open an optionsDialog with specified parameters $jsOpenOptions = '<script language="javascript" type="text/javascript">'; ! $jsOpenOptions .= 'javascript:'; ! $jsOpenOptions .= "window.open('".s($CFG->wwwroot)."/mod/quiz/questiontypes/rqp/options.php?optionstype=$optionType&typeid=$type&courseid=$course&userid=$user&quizid=$quiz','optionspopup', ! 'left=20,top=20,width=500,height=500,toolbar=0,resizable=1,scrollbars=yes')"; ! $jsOpenOptions .= '</script>'; echo $jsOpenOptions; + } + + //Get a list of RQP question types from the quiz_rqp_types table and return to calling function + //Used in course/quiz level options, to set the options for a particular RQP question type + function quiz_rqp_get_types() + { + if (!$rqp_types = get_records('quiz_rqp_types')) { + return false; + } + + //else + $rqpQuestionTypes = array(); + + foreach($rqp_types as $rqp_type) { + $rqpQuestionTypes[$rqp_type->id] = $rqp_type->name; + } + + return $rqpQuestionTypes; } *************** *** 193,207 **** } ! function quiz_rqp_debug_soap($item) { ! global $CFG; ! if ($CFG->debug) { ! echo 'Here is the dump of the soap fault:<pre>'; ! var_dump($item); ! echo '<pre>'; ! } } //Returns a server url given a specified type, by randomly selecting a server ! function quiz_rqp_get_server($typeid) { if (!$servers = get_records('quiz_rqp_servers', 'typeid', $typeid)) { --- 273,448 ---- } ! //Used in types.php to ensure that the server can be communicated to, before sending web service request ! function quiz_rqp_check_server($url, $serverid=0) { ! $timeLimit = 20; ! ! if ($serverid!=0) { ! $server = get_record('quiz_rqp_servers', 'id', $serverid); ! $urldata = parse_url($server->url); ! } ! ! else $urldata = parse_url($url); ! ! if(!array_key_exists('port', $urldata)) { ! $urldata['port']=80; ! } ! ! $sock = @fsockopen($urldata['host'],$urldata['port'], $errno, $errmsg, $timeLimit); //run silently ! ! @stream_set_timeout($sock, 2); ! @stream_set_blocking($sock, false); ! ! //If connection established ! if ($sock) { ! @fclose($sock); ! return true; ! } ! ! //No connection could be established ! else if (!$sock) { ! @fclose($sock); ! return false; ! } ! } ! function quiz_rqp_initialise() { ! global $rqpTypes; ! ! //Go through each type and each server, adding [] -> [type] -> [serverid],[url] to $rqpType array ! if ($types = get_records('quiz_rqp_types')) ! { ! foreach ($types as $type) { ! if ($servers = get_records('quiz_rqp_servers', 'typeid', $type->id)) { ! ! shuffle($servers); ! ! foreach ($servers as $server) { ! $rqpTypes[$type->id][] = $server->id; ! } ! } ! } ! } ! } ! ! //Will be called by the types.php function, if a server is added/removed ! //Check that this type exists within $rqpTypes, if not, add it and the new server ! function quiz_rqp_add_server($typeid, $serverid) { ! global $rqpTypes; ! ! $rqpTypes[$typeid][] = $serverid; } + //This function called by types.php function if a server is removed + //In this case, check if there are any other servers of a type, if not remove that type + function quiz_rqp_remove_server($typeid, $serverid) { + global $rqpTypes; + + if(array_key_exists($typeid, $rqpTypes)) { + $servers = $rqpTypes[$typeid]; + + for ($i=0;$i<count($servers);$i++) { + + if($servers[$i]==$serverid) { + //We have found our match, now remove it + $servers = array_delete($servers, $i); + + break; + } + } + + //Count the nunber of $servers left + if(count($servers)==0) { + array_delete($rqpTypes, $typeid); + } + + else { //if at least one server left of that type + //Update server list + $rqpTypes[$typeid] = $servers; + } + } + } + + //Removes an item indexed by a $item key. Then re-orders + function array_delete($array, $item) { + if (isset($array[$item])) + unset($array[$item]); + + return array_merge($array); + + } + + //Responsible for initialising server list and keeping up to date, with servers that work the best up the top! + function quiz_rqp_get_server($typeid) { + global $rqpTypes; + + $timeLimit = 20; + + if (empty($rqpTypes)) { + quiz_rqp_initialise(); + } + + //Now check for the typeid that a server exists that we can use + if(array_key_exists($typeid, $rqpTypes)) { + if(count($rqpTypes[$typeid]>0)) { + $servers = $rqpTypes[$typeid]; //help readability only + + for ($i=0;$i<count($servers);$i++) { //iterate through each server in order! + $server = get_record('quiz_rqp_servers', 'id', $servers[$i]); + + $urldata = parse_url($server->url); + if(!array_key_exists('port', $urldata)) { + $urldata['port']=80; + } + + $sock = fsockopen($urldata['host'],$urldata['port'], $errno, $errmsg, $timeLimit); + + stream_set_timeout($sock, 2); + stream_set_blocking($sock, false); + + //If connection established + if ($sock) { + fclose($sock); + $temp = $servers[$i]; + $servers = array_delete($servers, $i); //Remove from original position + array_unshift($servers, $temp); //Push this server up to the top of the new list + + unset($temp); + break; + } + + //No connection could be established, keep iterating + else if (!$sock) { + $server=false; + fclose($sock); + } + } + + //Remember to update $rqpTypes array + $rqpTypes[$typeid] = $servers; + } + + //count = 0 + else $server = false; + } + + //no servers of particular type found + else $server = false; + + return $server; //either false or an actual server! + } + + //Returns a server url given a specified type, by randomly selecting a server ! //<TODO>Need to keep a single list of servers, possibly within session variable, check with Gustav ! //takes rqpType as a global array ! function quiz_rqp_get_server_old($typeid) { ! global $rqpTypes; ! ! $timeLimit = 20; //default time limit before timeout for particular server ! ! //Initialise list of servers within $rqpTypes, which will be managed by this function ! if (empty($rqpTypes)) { ! quiz_rqp_initialise(); ! } ! if (!$servers = get_records('quiz_rqp_servers', 'typeid', $typeid)) { *************** *** 209,242 **** } ! shuffle($servers); ! return $servers[0]; ! } ! ! function quiz_rqp_get_server_old($typeid) { ! ! if (!array_key_exists($typeid, $remote_connections)) { ! // get the available servers ! if (!$servers = get_records('quiz_rqp_servers', 'typeid', $typeid)) { ! // we don't have a server for this question type ! return false; ! } ! // put them in a random order ! shuffle($servers); ! // go through them and try to connect to each until we are successful ! foreach ($servers as $server) { ! if ($remote_connections[$typeid] = rqp_connect($server->url)) { ! break; // we have a connection ! } else { ! // We have a dead server here, should somehow flag that ! } } } ! // check that we did get a connection ! if (!$remote_connections[$typeid]) { ! unset($remote_connections[$typeid]); ! return false; ! } ! return true; } ?> --- 450,485 ---- } ! shuffle($servers); //put servers in a random order ! foreach ($servers as $server) { ! //go through each of them and try to communicate with server till successful ! $urldata = parse_url($server->url); ! if(!array_key_exists('port', $urldata)) { ! $urldata['port']=80; } + + $sock = fsockopen($urldata['host'],$urldata['port'], $errno, $errmsg, $timeLimit); + + stream_set_timeout($sock, 2); + stream_set_blocking($sock, false); + + //If connection established + if ($sock) { + fclose($sock); + + //push this server up to the top of the new list + break; + } + + //No connection could be established + //Keep iterating + //<TODO> What do we do with this dead server + else if (!$sock) { + $server=false; + fclose($sock); + } } ! ! return $server; //either false or an actual server! } ?> Index: questiontype.php =================================================================== RCS file: /cvsroot/stack/stack-1-0/scripts/rqp/moodle_16_rqp/quiz/questiontypes/rqp/questiontype.php,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** questiontype.php 12 Sep 2005 09:46:59 -0000 1.1 --- questiontype.php 5 Oct 2005 11:43:44 -0000 1.2 *************** *** 12,16 **** require_once($CFG->dirroot . '/mod/quiz/questiontypes/rqp/lib.php'); - //require_once($CFG->dirroot . '/mod/quiz/questiontypes/rqp/remote.php'); require_once($CFG->dirroot . '/mod/quiz/questiontypes/rqp/RQPv1p0Client.php'); --- 12,15 ---- *************** *** 315,319 **** */ function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { ! global $CFG; require_once("RQPv1p0Client.php"); --- 314,324 ---- */ function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) { ! global $CFG, $USER; ! ! $courseid = $cmoptions->course; ! $typeid = $question->options->type; ! $userid = $USER->id; ! $quizid = $cmoptions->id; //Is this the quizid? ! $struseroptions = get_string('userOptions','quiz'); require_once("RQPv1p0Client.php"); *************** *** 336,345 **** //Initialise render parameters $render['source'] = $question->options->source; ! $render['options'] = array ( 'admin' => '' , ! 'teacher' => 'current quiz name', ! 'user' => '', ! 'user-agent' => '', ! 'accept' => '', ! 'language' => ''); $render['persistentData']= ''; --- 341,350 ---- //Initialise render parameters $render['source'] = $question->options->source; ! $render['options'] = array ( 'admin' => quiz_rqp_get_admin_options($question->options->type) , ! 'teacher' => quiz_rqp_get_teacher_options($quizid, $courseid, $typeid), ! 'user' => quiz_rqp_get_user_options($USER->id, $question->options->type), ! 'user-agent' => $_SERVER['HTTP_USER_AGENT'], ! 'accept' => $_SERVER['HTTP_ACCEPT'], ! 'language' => current_language()); $render['persistentData']= ''; *************** *** 362,365 **** --- 367,371 ---- //Check SOAP fault has not been returned if (is_instance_of($output,'nbSOAPFault')) { + print_r($output); notify('SOAP fault returned. Please try again!'); unset($output); *************** *** 405,409 **** //5. Any STACK responses ! if ($options->validation) { if (!empty($output['output']['response'])) { echo '<div class="RQPresponse">'; --- 411,416 ---- //5. Any STACK responses ! if ($options->validation) { ! if (!empty($output['output']['response'])) { echo '<div class="RQPresponse">'; *************** *** 414,421 **** //6. Answer where required ! if (!empty($output['output']['answer'])) { echo '<div class="RQPanswer">'; echo html_entity_decode($output['output']['answer']); echo '</div>'; } --- 421,430 ---- //6. Answer where required ! if ($options->correct_responses) { ! if (!empty($output['output']['answer'])) { echo '<div class="RQPanswer">'; echo html_entity_decode($output['output']['answer']); echo '</div>'; + } } *************** *** 429,432 **** --- 438,446 ---- } + if ($server->properties & RQP_SERVER_USEROPTIONS) { + echo "<a title=\"$struseroptions\" href=\"javascript:void();\" onClick=\"openpopup('/mod/quiz/questiontypes/rqp/options.php?typeid=$server->typeid&userid=$USER->id&optionstype=userOptions','useroptions', + 'scrollbars=yes,resizable=yes,width=500,height=500', false)\">Edit user options</a>\n"; + } + // Remove the render output created during grading (if any) unset($state->options->renderoutput); *************** *** 478,482 **** */ function grade_responses(&$question, &$state, $cmoptions) { ! global $CFG; require_once("RQPv1p0Client.php"); --- 492,501 ---- */ function grade_responses(&$question, &$state, $cmoptions) { ! global $CFG, $USER; ! ! $courseid = $cmoptions->course; ! $typeid = $question->options->type; ! $userid = $USER->id; ! $quizid = $cmoptions->id; //Is this the quizid? require_once("RQPv1p0Client.php"); *************** *** 488,502 **** //Initialise render parameters $render['source'] = $options->source; ! $render['options'] = array ( 'admin' => '' , ! 'teacher' => 'current quiz name', ! 'user' => '', ! 'user-agent' => '', ! 'accept' => '', ! 'language' => ''); ! $render['persistentData']= ''; ! ! $render['directives'] = array(''); ! $render['mimetypes'] = array('text/html');; $render['namePrefix'] = $question->name_prefix; --- 507,519 ---- //Initialise render parameters $render['source'] = $options->source; ! $render['options'] = array ( 'admin' => quiz_rqp_get_admin_options($typeid) , ! 'teacher' => quiz_rqp_get_teacher_options($quizid, $courseid, $typeid), ! 'user' => quiz_rqp_get_user_options($userid, $typeid), ! 'user-agent' => $_SERVER['HTTP_USER_AGENT'], ! 'accept' => $_SERVER['HTTP_ACCEPT'], ! 'language' => current_language()); ! $render['persistentData']= $state->options->persistent_data; ! $render['directives'] = array(''); $render['mimetypes'] = array('text/html');; $render['namePrefix'] = $question->name_prefix; *************** *** 512,518 **** } if (QUIZ_EVENTGRADE == $state->event ! || QUIZ_EVENTCLOSE == $state->event) ! { $render['directives'][] = 'advanceState'; } --- 529,536 ---- } + //Advance the state where applicable if (QUIZ_EVENTGRADE == $state->event ! || QUIZ_EVENTCLOSE == $state->event ! || QUIZ_EVENTVALIDATE == $state->event) { $render['directives'][] = 'advanceState'; } *************** *** 536,539 **** --- 554,558 ---- if (is_instance_of($output,'nbSOAPFault')) { notify('SOAP fault returned. Please try again!'); + print_r($output); unset($output); return false; *************** *** 592,595 **** --- 611,615 ---- $link->name = 'managetypes'; $link->link = 'types.php'; + return array($link); } Index: editquestion.php =================================================================== RCS file: /cvsroot/stack/stack-1-0/scripts/rqp/moodle_16_rqp/quiz/questiontypes/rqp/editquestion.php,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** editquestion.php 12 Sep 2005 09:46:59 -0000 1.1 --- editquestion.php 5 Oct 2005 11:43:44 -0000 1.2 *************** *** 3,7 **** require_once($CFG->dirroot . '/mod/quiz/questiontypes/rqp/lib.php'); ! $strbacktoquiz = get_string("backtoquiz", "quiz"); //Here we must decide whether to display the RQP servers authoring form, or use the generic one --- 3,8 ---- require_once($CFG->dirroot . '/mod/quiz/questiontypes/rqp/lib.php'); ! $strbacktoquiz = get_string("backtoquiz", "quiz"); ! $struseroptions = get_string("userOptions", "quiz"); //Here we must decide whether to display the RQP servers authoring form, or use the generic one *************** *** 16,20 **** $question->options->type = $typeid; $question->options->source = ''; - //$question->options->format = ''; } --- 17,20 ---- *************** *** 47,52 **** 'accept' => '', 'language' => ''); ! ! $render['persistentData']= ''; //not used in authoring $render['directives'] = array('edit'); --- 47,57 ---- 'accept' => '', 'language' => ''); ! ! if (!empty($SESSION->persistent_data)) { ! $render['persistentData']= $SESSION->options->persistent_data; //not used in authoring ! } ! ! //On first render operation ! else $render['persistentData'] = ''; $render['directives'] = array('edit'); *************** *** 77,80 **** --- 82,88 ---- $render['namePrefix'],$render['itemBase'], $render['resourceBase'],$render['tempfileBase']); + + //Set any persistent data in the session variable + $SESSION->persistent_data = $response['persistentData']; //Construct RQP server form: we always post back to question.php to perform form processing *************** *** 83,87 **** echo '<input type="hidden" name="type" value="'.$type->id.'"/>'; //TODO: both type and typeid are used, echo '<input type="hidden" name="typeid" value="'.$type->id.'"/>'; //but represent same value! - //$typeid var disused echo '<input type="hidden" name="completion" value="'.$response['outcomeVars']['completion'].'"/>'; --- 91,94 ---- *************** *** 90,93 **** --- 97,106 ---- echo html_entity_decode($response['output']['body']); + //Pop-up for user options + if ($server->properties & RQP_SERVER_USEROPTIONS) { + echo "<a title=\"$struseroptions\" href=\"javascript:void();\" onClick=\"openpopup('/mod/quiz/questiontypes/rqp/options.php?typeid=$typeid&userid=$USER->id&optionstype=userOptions','useroptions', + 'scrollbars=yes,resizable=yes,width=500,height=500', false)\">Edit user options</a>\n"; + } + if ("complete"!=$response['outcomeVars']['completion']) { $QUIZ_QTYPES[$question->qtype]->print_replacement_options($question, $course, $contextquiz); *************** *** 111,114 **** --- 124,128 ---- echo '<input type="hidden" name="source" value="'.$response['outcomeVars']['source'].'"/>'; echo '<input type="hidden" name="name" value="'.$response['output']['title'].'"/>'; + } Index: options.php =================================================================== RCS file: /cvsroot/stack/stack-1-0/scripts/rqp/moodle_16_rqp/quiz/questiontypes/rqp/options.php,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** options.php 12 Sep 2005 09:46:59 -0000 1.1 --- options.php 5 Oct 2005 11:43:44 -0000 1.2 *************** *** 5,18 **** require_once($CFG->dirroot . '/mod/quiz/questiontypes/rqp/lib.php'); ! $type = optional_param('typeid', 0, PARAM_INT); //if of RQP type for which to set options for ! //$course = optional_param('courseid', 0, PARAM_INT); ! //$quiz = optional_param('quizid', 0, PARAM_INT); ! $optionsType = optional_param('optionstype'); //type of options that should be displayed ! // Check user admin require_login(); ! if (!isadmin()) { error('You need to be an admin user to use this page.', $CFG->wwwroot . '/login/index.php'); } if (!$site = get_site()) { --- 5,26 ---- require_once($CFG->dirroot . '/mod/quiz/questiontypes/rqp/lib.php'); ! require_variable($typeid); //rqp type to set options for. Necessary in all cases for setting options ! require_variable($optionstype); //options type: one of adminOptions, teacherOptions, userOptions. ! $course = optional_param('courseid', 0, PARAM_INT); //if setting teacher options at course level ! $quiz = optional_param('quizid', 0, PARAM_INT); //if setting teacher options at quiz level ! $user = optional_param('userid', 0, PARAM_INT); //if setting user options during rendering ! ! // Check for correct user require_login(); ! ! //If called in context of adminOptions - must be the administrator ! if (!isadmin() && empty($course) && empty($quiz) && empty($user)) { error('You need to be an admin user to use this page.', $CFG->wwwroot . '/login/index.php'); } + + if (!isteacher() && !empty($course) && !empty($quiz)) { //If called in context of teacherOptions - must be teacher of course + error('You need to be a teacher user to use this page.', $CFG->wwwroot . '/login/index.php'); + } if (!$site = get_site()) { *************** *** 21,96 **** $strmodulename = get_string('modulename', 'quiz'); ! $stritemtypes = get_string('itemtypes', 'quiz'); ! $navigation = '<a href="' . s($CFG->wwwroot) . '/' . s($CFG->admin) . '/index.php">' . get_string('admin') . '</a> -> ' . ! '<a href="' . s($CFG->wwwroot) . '/' . s($CFG->admin) . '/configure.php">' . get_string('configuration') . '</a> -> ' . ! '<a href="' . s($CFG->wwwroot) . '/' . s($CFG->admin) . '/modules.php">' . get_string('managemodules') . '</a> -> ' . ! '<a href="' . s($CFG->wwwroot) . '/' . s($CFG->admin) . '/module.php?module=quiz&sesskey=' . sesskey() . '">' . ! get_string('modulename', 'quiz') . '</a> -> ' . $stritemtypes; ! print_header($site->shortname . ': ' . $strmodulename . ': ' . $stritemtypes, $site->fullname, $navigation, '', '', true, '', ''); ! ! if ($type==0) { ! notify(get_string('invalidrqptype','quiz')); ! exit(); ! } ! if ($optionsType==NULL) { ! notify(get_string('invalidoptiontype','quiz')); ! } ! if ($form = data_submitted() and confirm_sesskey()) ! { ! //<TODO: Take the appropriate action depending on whether called in the context of student, teacher or admin options> ! //For now we shall just serialise into adminOptions field ! switch ($optionsType) { ! case('adminOptions') : ! { ! //Perform render operation with fields present in input data ! //1. Get type in order to get namePrefix for ! if (!$rqpType = get_record('quiz_rqp_types', 'id', $type)) { ! notify(get_string('invalidrqptype','quiz')); ! exit(); ! } ! //1. Select a server to render options for: ! if (!$server = quiz_rqp_get_server($type)) { ! notify(get_string('noserverforrqptype','quiz')); ! exit(); ! } ! ! require_once("RQPv1p0Client.php"); ! $rqpserver = new RQPv1p0(); ! $rqpserver->Url = $server->url; ! ! $render['source']="$optionsType"; //For options, source=adminOptions,teacherOptions,userOptions ! ! $render['persistentData']=''; ! $render['directives']=array('edit'); ! ! $render['mimetypes']=array('text/html');; ! $render['namePrefix']=$rqpType->name; ! $render['itemBase']=''; ! ! //Check presence of form fields which are to be processed ! if (empty($form)) { ! $render['inputData']=array(); ! } ! ! else { ! $render['inputData']=quiz_rqp_parse_input($form,$render['namePrefix']); ! } ! ! $response = $rqpserver->RQP_Render($render['source'],array(), ! $render['persistentData'],$render['inputData'], ! $render['directives'],$render['mimetypes'], ! $render['namePrefix'],$render['itemBase'], ! '',''); //Now check 'options' outcome variable for a serialised options string ! if ($old = get_record('quiz_rqp_types', 'id', $type)) { ! //Update adminOptions field ! $old->options = $response['outcomeVars']['options']; //Place adminOptions string into quiz_rqp_types table if (!update_record('quiz_rqp_types', $old)) { ! notice("Could not update current rqp type field: adminOptions! (type=$type)"); } --- 29,102 ---- $strmodulename = get_string('modulename', 'quiz'); ! $stroptions = get_string('options', 'quiz'); ! print_header($site->shortname . ': ' . $strmodulename . ': ' . $stroptions, $site->fullname, '', '', '', true, '', ''); ! //Successive attempts within options.php script ! if ($form = data_submitted() and confirm_sesskey()) { ! while (isset($form->add)) { // using like if but with support for break ! ! //Do not process request where optionsType is not one of the allowed strings ! if ($optionstype!= 'adminOptions' && $optionstype!='teacherOptions' && $optionstype!='userOptions') { ! notify(get_string('invalidoptiontype','quiz')); ! exit(); ! } ! ! //Perform render operation with fields present in input data ! //1. Get type in order to get namePrefix for ! if (!$rqpType = get_record('quiz_rqp_types', 'id', $typeid)) { ! notify(get_string('invalidrqptype','quiz')); ! exit(); ! } ! //1. Select a server to render options for: ! if (!$server = quiz_rqp_get_server($typeid)) { ! notify(get_string('noserverforrqptype','quiz')); ! exit(); ! } ! ! require_once("RQPv1p0Client.php"); ! ! $rqpserver = new RQPv1p0(); ! $rqpserver->Url = $server->url; ! ! $render['source']="$optionstype"; //For options, source=adminOptions,teacherOptions,userOptions ! $render['persistentData']=$form->persistentData; //Use any persistent data as request from original response ! $render['directives']=array('edit'); ! $render['mimetypes']=array('text/html');; ! $render['namePrefix']=$rqpType->name; ! $render['itemBase']=''; ! $render['resourceBase'] =''; ! $render['tempfileBase'] =''; ! ! //Check presence of form fields which are to be processed ! if (empty($form)) { ! $render['inputData']=array(); ! } ! ! else { ! $render['inputData']=quiz_rqp_parse_input($form,$render['namePrefix']); ! } ! ! $response = $rqpserver->RQP_Render($render['source'],array(), ! $render['persistentData'],$render['inputData'], ! $render['directives'],$render['mimetypes'], ! $render['namePrefix'],$render['itemBase'], ! $render['resourceBase'],$render['tempfileBase']); ! ! //Do not proceed with updating options unless RQP server has finished ! if($response['outcomeVars']['completion']!='complete') { ! break; ! } + switch ($optionstype) { + //This block performs the updating of the options + case('adminOptions') : { //Now check 'options' outcome variable for a serialised options string ! if ($old = get_record('quiz_rqp_types', 'id', $typeid)) { ! $old->options = $response['outcomeVars']['options']; //Update 'options' field //Place adminOptions string into quiz_rqp_types table if (!update_record('quiz_rqp_types', $old)) { ! notice("Could not update current rqp type field: adminOptions! (type=$typeid)"); } *************** *** 98,133 **** notice("Updated administrator options"); } ! } ! break; } ! case('teacherOptions') : ! { ! //Place teacherOptions string into either: ! //1. quiz_rqp_course_options table, if called in context of course (i.e. courseid additional param is set) ! //2. quiz_rqp, if called in context of a quiz (i.e. quizid additional param is set) break; } ! case('userOptions') : ! { ! //Place userOptions string into: ! //1. quiz_rqp_user_options table, where 'userid' additional param will be set! break; } ! } ! } ! //Render the options //1. Get type in order to get namePrefix for ! if (!$rqpType = get_record('quiz_rqp_types', 'id', $type)) { notify(get_string('invalidrqptype','quiz')); exit(); } //2. Select a server to render options for: ! if (!$server = quiz_rqp_get_server($type)) { notify(get_string('noserverforrqptype','quiz')); exit(); --- 104,233 ---- notice("Updated administrator options"); } ! } ! ! //Serious error here, RQP question type does not exist for options being set ! else { ! notice("Could not retrieve RQP type $typeid"); ! } ! break; } ! case('teacherOptions') : { ! if (!empty($course)) { ! //Set options should be saved in quiz_rqp_course_options ! //1. Check if course options exist already, and overwrite ! if ($old = get_record('quiz_rqp_course_options', 'courseid', $course, 'typeid', $typeid)) { ! $old->options = $response['outcomeVars']['options']; ! ! if (!update_record('quiz_rqp_course_options', $old)) { ! notice("Could not update course specific teacherOptions (type=$typeid), (course=$course)"); ! } ! ! else { ! notice("Updated course teacher options"); ! } ! } ! ! //2. Where course options do not exist ! else { ! //Construct a course options object ! $course_options->courseid = $courseid; ! $course_options->typeid = $typeid; ! $course_options->options = $response['outcomeVars']['options']; ! ! if (!$course_options->id = insert_record('quiz_rqp_course_options', $course_options)) { ! notice("Could not save course specific teacherOptions (type=$typeid), (course=$courseid)"); ! } ! } ! } ! else if (!empty($quiz)) { ! //Set options should be saved in quiz_rqp_quiz_options table ! //1. Check if quiz options exist already, and prepare to overwrite ! if ($old = get_record('quiz_rqp_quiz_options', 'quizid', $quiz, 'typeid', $typeid)) { ! $old->options = $response['outcomeVars']['options']; ! ! if (!update_record('quiz_rqp_quiz_options', $old)) { ! notice("Could not update quiz specific teacherOptions (type=$typeid), (quiz=$quiz)"); ! } ! ! else { ! notice("Updated quiz teacher options"); ! } ! } ! ! //2. Where quiz options do not exist ! else { ! //Construct a course options object ! $quiz_options->quizid = $quiz; ! $quiz_options->typeid = $typeid; ! $quiz_options->options = $response['outcomeVars']['options']; ! ! if (!$quiz_options->id = insert_record('quiz_rqp_quiz_options', $quiz_options)) { ! notice("Could not save course specific teacherOptions (type=$typeid), (quiz=$quiz)"); ! } ! } ! } ! ! //Where $course and $quiz are both unset ! else { ! notify(get_string('errorloadteacheroptions','quiz')); ! exit(); ! } ! break; } ! case('userOptions') : { ! if (!empty($user)) { ! //Set options saved into quiz_rqp_user_options table ! //1. Check if user options exist already, and prepare to overwrite ! if ($old = get_record('quiz_rqp_user_options', 'userid', $user, 'typeid', $typeid)) { ! $old->options = $response['outcomeVars']['options']; ! ! if (!update_record('quiz_rqp_user_options', $old)) { ! notice("Could not update user options for the current RQP question type (type=$typeid), (user=$user)"); ! } ! ! else { ! notice("Updated user options for current RQP type"); ! } ! } ! ! //2. Where quiz options do not exist ! else { ! //Construct a course options object ! $user_options->userid = $user; ! $user_options->typeid = $typeid; ! $user_options->options = $response['outcomeVars']['options']; ! ! if (!$user_options->id = insert_record('quiz_rqp_user_options', $user_options)) { ! notice("Could not save user options for the current RQP question type (type=$typeid), (user=$user)"); ! } ! } ! } ! ! //Where $user is unset - cannot set user options without this ! else { ! notify(get_string('errorloaduseroptions','quiz')); ! exit(); ! } ! break; } ! } ! } } + //End of data_submitted ! //Initally render the options //1. Get type in order to get namePrefix for ! if (!$rqpType = get_record('quiz_rqp_types', 'id', $typeid)) { notify(get_string('invalidrqptype','quiz')); exit(); } //2. Select a server to render options for: ! if (!$server = quiz_rqp_get_server($typeid)) { notify(get_string('noserverforrqptype','quiz')); exit(); *************** *** 136,141 **** else { ! //Check if response obtained by above render operation if (!isset($response)) { //Otherwise initial render operation require_once("RQPv1p0Client.php"); --- 236,242 ---- else { ! //Check and use response obtained by above render operation, if one exists if (!isset($response)) { + //Otherwise initial render operation require_once("RQPv1p0Client.php"); *************** *** 143,150 **** $rqpserver->Url = $server->url; ! $render['source']="$optionsType"; //For options, source=adminOptions,teacherOptions,userOptions ! $render['persistentData']=''; ! $render['inputData']=array(); $render['directives']=array('edit'); --- 244,251 ---- $rqpserver->Url = $server->url; ! $render['source']="$optionstype"; //For options, source=adminOptions,teacherOptions,userOptions ! $render['persistentData']=''; //Blank for initial response ! $render['inputData']=array(); //Blank for initial options render op $render['directives']=array('edit'); *************** *** 152,161 **** $render['namePrefix']=$rqpType->name; $render['itemBase']=''; ! $response = $rqpserver->RQP_Render($render['source'],array(), $render['persistentData'],$render['inputData'], $render['directives'],$render['mimetypes'], $render['namePrefix'],$render['itemBase'], ! '',''); } } --- 253,340 ---- $render['namePrefix']=$rqpType->name; $render['itemBase']=''; + $render['resourceBase'] = ''; + $render['tempfileBase'] = ''; ! //We may have some options already set by user to pass in render operation: ! $render['options'] = array('user-agent' => $_SERVER['HTTP_USER_AGENT'], ! 'accept' => $_SERVER['HTTP_ACCEPT'], ! 'language' => current_language()); //Moodle language ! ! //Load initial options - check the context in which this page was called: ! switch ($optionstype) { ! case('adminOptions') : { ! //<TODO> attempt to get a server within the type that supports admin options ! if ($server->properties & !RQP_SERVER_ADMINOPTIONS) { ! notify(get_string('noadminoptionstoset', 'quiz')); ! exit(); ! } ! ! $rqptype = get_record('quiz_rqp_types','id',$typeid); ! $render['options']['admin'] = $rqptype->options; ! ! break; ! } ! ! case('teacherOptions') : { ! //<TODO> attempt to get a server within the type that supports teacher options ! if ($server->properties & !RQP_SERVER_TEACHEROPTIONS) { ! notify(get_string('noteacheroptionstoset', 'quiz')); ! exit(); ! } ! ! //Where $course and $quiz are both unset ! if (empty($course) && empty($quiz)) { ! notify(get_string('errorloadteacheroptions','quiz')); ! exit(); ! } ! ! //teacher options called in context of course - get course options for particular RQP type ! else if (!empty($course)) { ! $rqptype = get_record('quiz_rqp_course_options', 'courseid', $course, 'typeid', $typeid); ! $render['options']['teacher'] = $rqptype->options; ! } ! ! //teacher options called in context of quiz - get quiz options for particualr RQP type ! else if (!empty($quiz)) { ! $rqptype = get_record('quiz_rqp_quiz_options', 'quizid', $quiz, 'typeid', $typeid); ! $render['options']['teacher'] = $rqptype->options; ! } ! ! break; ! } ! ! case('userOptions') : { ! //<TODO> attempt to get a server within the type that supports user options ! if ($server->properties & !RQP_SERVER_USEROPTIONS) { ! notify(get_string('nouseroptionstoset', 'quiz')); ! exit(); ! } ! ! //Where $user is unset - cannot set user options without this ! if (empty($user)) { ! notify(get_string('errorloaduseroptions','quiz')); ! exit(); ! } ! ! //user options ! $rqptype = get_record('quiz_rqp_user_options', 'userid', $user, 'typeid', $typeid); ! $render['options']['user'] = $rqptype->options; ! ! break; ! } ! ! default: { ! notify(get_string('invalidoptiontype','quiz')); ! exit(); ! ! break; ! } ! } ! ! $response = $rqpserver->RQP_Render($render['source'],$render['options'], $render['persistentData'],$render['inputData'], $render['directives'],$render['mimetypes'], $render['namePrefix'],$render['itemBase'], ! $render['resourceBase'],$render['tempfileBase']); } } *************** *** 163,171 **** $addButton = '<input type="submit" value="save options" name="add" />'; $cancelButton = '<input type="button" onclick="window.close()" value="cancel"\" />'; ! ! print_heading_with_help('Administrator options'); ! echo '<form action="options.php?typeid='.$type.'&optionstype='.$optionsType.'" method="post">'; echo '<center>'; echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />'; echo html_entity_decode($response['output']['body']); echo '<br/><br/>'.$addButton; --- 342,353 ---- $addButton = '<input type="submit" value="save options" name="add" />'; $cancelButton = '<input type="button" onclick="window.close()" value="cancel"\" />'; ! $stroptionstoset = get_string($optionstype, 'quiz'); ! ! //Actual form ! print_heading_with_help($stroptionstoset, 'options', 'quiz'); ! echo '<form action="'."options.php?optionstype=$optionstype&typeid=$typeid&courseid=$course&userid=$user&quizid=$quiz".'" method="post">'; echo '<center>'; echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />'; + echo '<input type="hidden" name="persistentData" value="'.$response['persistentData'].'" />'; //cache any persistent data from RQP server echo html_entity_decode($response['output']['body']); echo '<br/><br/>'.$addButton; Index: types.php =================================================================== RCS file: /cvsroot/stack/stack-1-0/scripts/rqp/moodle_16_rqp/quiz/questiontypes/rqp/types.php,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** types.php 12 Sep 2005 09:46:59 -0000 1.1 --- types.php 5 Oct 2005 11:43:44 -0000 1.2 *************** *** 15,19 **** require_login(); if (!isadmin()) { ! error('You need to be an admin user to use this page.', $CFG->wwwroot . '/login/index.php'); } --- 15,19 ---- require_login(); if (!isadmin()) { ! error(get_string('adminuseronly', 'quiz'), $CFG->wwwroot . '/login/index.php'); } *************** *** 37,53 **** while (isset($form->add)) { // using like if but with support for break ! //check url was given ! if (empty($form->url)) { notify(get_string('missingitemtypeurl', 'quiz')); break; ! } ! //Check url corresponds to valid format ! else if (!preg_match('/^(http|https):\/\//', $form->url)) ! { notify(get_string('incorrecturlused', 'quiz')); $straddtypeurl = $form->url; break; ! } require_once("RQPv1p0Client.php"); --- 37,60 ---- while (isset($form->add)) { // using like if but with support for break ! //check url was given ! if (empty($form->url)) { notify(get_string('missingitemtypeurl', 'quiz')); break; ! } ! //Check url corresponds to valid format ! else if (!preg_match('/^(http|https):\/\//', $form->url)) ! { notify(get_string('incorrecturlused', 'quiz')); $straddtypeurl = $form->url; break; ! } ! ! if (!quiz_rqp_check_server($form->url)) ! { ! notify(get_string('servernotresponding', 'quiz')); ! $straddtypeurl = $form->url; ! break; ! } require_once("RQPv1p0Client.php"); *************** *** 66,78 **** //If SOAP fault is that which the method invoked is not implemented if ($serverinfo->faultcode=='notImplemented') { ! notify('This web server does not offer web services. Please try another'); } else if ($serverinfo->faultcode=='processingFailed') { ! notify('This server has experienced an error whilst processing your request. Please try again later'); ! } ! ! else { ! notify('Could not contact the web server specified. Please ensure you have used the correct URL'); } --- 73,81 ---- //If SOAP fault is that which the method invoked is not implemented if ($serverinfo->faultcode=='notImplemented') { ! notify(get_string('nowebservice', 'quiz')); } else if ($serverinfo->faultcode=='processingFailed') { ! notify(get_string('errorprocrequest', 'quiz').$serverinfo->faultstring); } *************** *** 92,96 **** } - $newType = false; --- 95,98 ---- *************** *** 106,110 **** if (!$type->id = insert_record('quiz_rqp_types', $type)) { ! error("Could not save type $type"); } } --- 108,112 ---- if (!$type->id = insert_record('quiz_rqp_types', $type)) { ! error(get_string('notsavetype', 'quiz')." $type"); } } *************** *** 130,134 **** if (!$server->id = insert_record('quiz_rqp_servers', $server)) { //Retrieve the server id for adding mimetypes to it ! error("Could not save server ".$form->url); } --- 132,136 ---- if (!$server->id = insert_record('quiz_rqp_servers', $server)) { //Retrieve the server id for adding mimetypes to it ! error(get_string('notsaveserver', 'quiz')." $form->url"); } *************** *** 145,149 **** if (!insert_record('quiz_rqp_mimetypes', $mimetype)) { ! error("Could not save mimetypes for server $form->url"); } } --- 147,151 ---- if (!insert_record('quiz_rqp_mimetypes', $mimetype)) { ! error(get_string('notsavemimetypes', 'quiz')." $form->url"); } } *************** *** 151,157 **** } ! //Now we need to retrieve any external resources STACK uses, i.e. JOME. Iterate through each URL ! /*foreach ($serverinfo['resources'] as $server_resource) ! { $split = explode('/',$server_resource) $length = count($split); --- 153,159 ---- } ! //Now we need to retrieve any external resources STACK uses, i.e. JOME. Iterate through each URL ! /*foreach ($serverinfo['resources'] as $server_resource) ! { $split = explode('/',$server_resource) $length = count($split); *************** *** 159,184 **** //may need to fopen here and get file info, if permissions allow! ! }*/ ! // print info about new server ! print_heading(get_string('serveradded', 'quiz')); ! quiz_rqp_print_serverinfo($serverinfo); ! if ($newType && $serverinfo['serverProperties']['adminOptions']) { ! //Now we must display options for type of server, if it is a new type ! $options = $type->id; ! break; ! } ! } ! else { //server already exists in database, inform user ! print_heading(get_string('serverexists', 'quiz')); ! break; ! } } } --- 161,185 ---- //may need to fopen here and get file info, if permissions allow! ! }*/ ! // print info about new server ! print_heading(get_string('serveradded', 'quiz')); ! quiz_rqp_print_serverinfo($serverinfo); ! if ($newType && $serverinfo['serverProperties']['adminOptions']) { ! //Now we must display options for type of server, if it is a new type ! $options = $type->id; ! break; ! } } ! else { //server already exists in database, inform user ! print_heading(get_string('serverexists', 'quiz')); ! break; ! } } } *************** *** 186,193 **** //Used when user wants to change options for a particular type - randomise the server used, also used when initally changing settings if ($options and confirm_sesskey()) { //retrieve admin options - //$server = quiz_rqp_get_server($options); //returns an arbitrary server given a type id - - //$server = get_record('quiz_rqp_servers', 'id', $options); - quiz_rqp_optionsDialog('adminOptions',$options); } --- 187,190 ---- *************** *** 199,202 **** --- 196,201 ---- //Delete the mimetypes associated with the deleted server delete_records('quiz_rqp_mimetypes', 'serverid', $delete); + + if (count_records('quiz_rqp_servers') == 0) { //Inform user no more RQP servers exist *************** *** 241,253 **** //If SOAP fault is that which the method invoked is not implemented if ($serverinfo->faultcode=='notImplemented') { ! notify('This web server does not offer web services. Please try another'); } else if ($serverinfo->faultcode=='processingFailed') { ! notify('This server has experienced an error whilst processing your request. Please try again later'); ! } ! ! else { ! notify('Could not contact the web server specified. Please ensure you have used the correct URL'); } --- 240,248 ---- //If SOAP fault is that which the method invoked is not implemented if ($serverinfo->faultcode=='notImplemented') { ! notify(get_string('nowebservice', 'quiz')); } else if ($serverinfo->faultcode=='processingFailed') { ! notify(get_string('errorprocrequest', 'quiz').$serverinfo->faultstring); } *************** *** 257,264 **** else { ! // print the info ! print_heading(get_string('serverinfo', 'quiz')); ! quiz_rqp_print_serverinfo($serverinfo); ! } } } --- 252,259 ---- else { ! // print the info ! print_heading(get_string('serverinfo', 'quiz')); ! quiz_rqp_print_serverinfo($serverinfo); ! } } } *************** *** 295,304 **** if ($types) { foreach ($types as $type) { if (!$servers = get_records('quiz_rqp_servers', 'typeid', $type->id)) { delete_records('quiz_rqp_types', 'id', $type->id); } else { foreach ($servers as $server) { ! //<TODO> Should iterate through servers to check that ServerInfo hasnt changed, and update if necessary $actions = '<a title="' . $strinfo . '" href="types.php?info='.$server->id.'&sesskey='.sesskey().'"><img src="../../../../pix/i/info.gif" border="0" alt="'.$strinfo.'" align="absbottom" /></a> <a title="'.$strdelete.'" href="types.php?delete='.$server->id.'&sesskey='.sesskey().'"><img src="../../../../pix/t/delete.gif" border="0" alt="'.$strdelete.'" /></a>'; $options = '<a title="' . $stroptions. '"href="types.php?options='.$type->id.'&sesskey='.sesskey().'"><img src="../../../../pix/i/edit.gif" border="0" alt="'.$stroptions.'" align="absbottom" /></a> '; --- 290,332 ---- if ($types) { foreach ($types as $type) { + + //Cleanup operation if (!$servers = get_records('quiz_rqp_servers', 'typeid', $type->id)) { delete_records('quiz_rqp_types', 'id', $type->id); + delete_records('quiz_rqp_user_options', 'typeid' , $type->id); //Delete options for disused types + delete_records('quiz_rqp_quiz_options', 'typeid' , $type->id); + delete_records('quiz_rqp_course_options', 'typeid' , $type->id); + } else { foreach ($servers as $server) { ! //Iterate through servers silently to check that ServerInfo hasnt changed, and update if necessary ! require_once("RQPv1p0Client.php"); ! ! $rqpserver = new RQPv1p0(); ! $rqpserver->Url = $server->url; ! ! $temp_serverinfo = $rqpserver->RQP_ServerInformation(); ! ! //Server properties flag production ! $temp_properties = 0; ! $temp_properties += empty($temp_serverinfo['serverProperties']['rendering']) ? 0 : RQP_SERVER_RENDERING; //key = rendering ! $temp_properties += empty($temp_serverinfo['serverProperties']['implicitCloning']) ? 0 : RQP_SERVER_IMPLICITCLONING; //key = implicitCloning ! $temp_properties += empty($temp_serverinfo['serverProperties']['explicitCloning']) ? 0 : RQP_SERVER_EXPLICITCLONING; //key = explicitCloning ! $temp_properties += empty($temp_serverinfo['serverProperties']['authoring']) ? 0 : RQP_SERVER_AUTHORING; //key = authoring ! $temp_properties += empty($temp_serverinfo['serverProperties']['adminOptions']) ? 0 : RQP_SERVER_ADMINOPTIONS; //key = adminOptions ! $temp_properties += empty($temp_serverinfo['serverProperties']['teacherOptions']) ? 0 : RQP_SERVER_TEACHEROPTIONS; //key = teacherOptions ! $temp_properties += empty($temp_serverinfo['serverProperties']['userOptions']) ? 0 : RQP_SERVER_USEROPTIONS; //key = userOptions ! ! if(($temp_serverinfo['version']!=$server->version) || ($temp_properties!=$server['properties'])) { //where information has changed ! //Propogate new information onto database ! $server->version = $temp_serverinfo['version']; ! $server->details = $temp_serverinfo['details']; ! ! $server->properties = $temp_properties; ! ! update_record('quiz_rqp_servers', $server); ! } ! $actions = '<a title="' . $strinfo . '" href="types.php?info='.$server->id.'&sesskey='.sesskey().'"><img src="../../../../pix/i/info.gif" border="0" alt="'.$strinfo.'" align="absbottom" /></a> <a title="'.$strdelete.'" href="types.php?delete='.$server->id.'&sesskey='.sesskey().'"><img src="../../../../pix/t/delete.gif" border="0" alt="'.$strdelete.'" /></a>'; $options = '<a title="' . $stroptions. '"href="types.php?options='.$type->id.'&sesskey='.sesskey().'"><img src="../../../../pix/i/edit.gif" border="0" alt="'.$stroptions.'" align="absbottom" /></a> '; |