major whitespace cleanup - fixed \r\n line-ending
authorskodak <skodak>
Wed, 20 Sep 2006 19:46:52 +0000 (19:46 +0000)
committerskodak <skodak>
Wed, 20 Sep 2006 19:46:52 +0000 (19:46 +0000)
53 files changed:
auth/fc/Readme.txt
auth/fc/fcFPP.php
auth/fc/lib.php
lang/README.txt
lang/en_utf8/help/assignment/quickgrade.html
lang/en_utf8/help/lesson/importppt.html
lang/en_utf8/help/lesson/questionoption.html
lang/en_utf8/help/lesson/questiontypes.html
lang/en_utf8/help/uploadgroups.html
lang/en_utf8/lams.php
login/change_password_form.html
mod/assignment/type/upload/mod.html
mod/chat/db/oci8po.sql
mod/chat/gui_header_js/chatmsg.php
mod/chat/gui_sockets/chatinput.php
mod/choice/db/oci8po.sql
mod/data/preset/Image Gallery/addtemplate.html
mod/data/preset/Image Gallery/csstemplate.css
mod/data/preset/Image Gallery/jstemplate.js
mod/data/preset/Image Gallery/listtemplate.html
mod/data/preset/Image Gallery/listtemplateheader.html
mod/data/preset/Image Gallery/singletemplate.html
mod/forum/db/oci8po.sql
mod/hotpot/hotpot-full.js
mod/hotpot/report/click/report.php
mod/hotpot/template/v6.php
mod/journal/db/mysql.sql
mod/journal/db/oci8po.sql
mod/resource/db/mysql.sql
mod/resource/db/oci8po.sql
mod/scorm/aicc.php
mod/scorm/api.php
mod/scorm/coefficientconfirm.php
mod/scorm/coefficientsetting.php
mod/scorm/datamodel.php
mod/scorm/index.php
mod/scorm/loadSCO.php
mod/scorm/mod.html
mod/scorm/sequencinglib.php
mod/scorm/styles.php
mod/scorm/suspend.php
mod/survey/db/mysql.sql
mod/survey/db/oci8po.sql
question/format/blackboard_6/format.php
question/format/learnwise/learnwise-example.xml
question/format/webct/TODO.txt
sso/hive/expired.php
sso/hive/lib.php
sso/hive/login.php
theme/chameleon/pix/mod/README.txt
theme/chameleon/ui/css_query.js
theme/chameleon/ui/sarissa.js
theme/metal/fonts.css

index fad629a..da49241 100644 (file)
@@ -1,71 +1,71 @@
-Moodle - FirstClass authentication module\r
------------------------------------------\r
-This module uses the FirstClass Flexible Provisining Protocol (FPP) to communicate between the FirstClass server\r
-and the Moodle host. \r
-\r
-Installation\r
-------------\r
-\r
-1. Enable FPP on the FirstClass server\r
-FPP is not doumented in the FirstClass documentation and is not enable by default.\r
-To enable the protocol you need to edit the file \FCPO\Server\Netinfo. Open the file and insert the\r
-following lines.  \r
-\r
-// TCP port for Flexible Provisioning Protocol (FPP).\r
-TCPFPPPORT = 3333\r
-\r
-\r
-2. Create an account on the FirstClass server with privilege "Subadministrator".\r
-Using the FPP protocoll this module logs in to the FirstClass server and issuess batch admin commands.\r
-Batch admin command can only be issued in the context of a user with subadministrative privileges.\r
-\r
-Default account name is "fcMoodle".\r
-\r
-\r
-3. Check that the FPP protocoll is working by running a Telnet session. If everyting is working you\r
-should get a "+0" answer from the server. \r
-\r
-> telnet yourhost.domain.com 3333\r
-+0\r
-\r
-Check that the "fcMoodle" is working by entering the following sequens of commands:\r
-\r
-> telnet yourhost.domain.com 3333\r
-+0\r
-fcMoodle\r
-+0\r
-\r
-the_password_you_gave_fcmoodle\r
-+0\r
-\r
-Get user some_user_id 1201\r
-\r
-1201 0 some_user_id\r
-+0\r
-\r
-\r
-\r
-4. On the Moodle host go to the directory where you have installed Moodle.\r
-Open the folder "auth", where all other authentication modules are installed,\r
- and create a new directory with the name "fc". \r
-\r
-Copy the files "config.html", "fcFPP.php" and "lib.php" to the "auth" directory.\r
-\r
-Now you need to add som strings to the language file. This distribution contains\r
-string for the English (en) and Swedish (sv) translation.\r
-\r
-Open the file "auth.php" in the folder "lang/sv" and paste the text from the file\r
-"auth.php - sv.txt" at the end of the file above the line "?>"\r
-\r
-Open the file "auth.php" in the folder "lang/en" and paste the text from the file\r
-"auth.php - en.txt" at the end of the file above the line "?>"\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
+Moodle - FirstClass authentication module
+-----------------------------------------
+This module uses the FirstClass Flexible Provisining Protocol (FPP) to communicate between the FirstClass server
+and the Moodle host. 
+
+Installation
+------------
+
+1. Enable FPP on the FirstClass server
+FPP is not doumented in the FirstClass documentation and is not enable by default.
+To enable the protocol you need to edit the file \FCPO\Server\Netinfo. Open the file and insert the
+following lines.  
+
+// TCP port for Flexible Provisioning Protocol (FPP).
+TCPFPPPORT = 3333
+
+
+2. Create an account on the FirstClass server with privilege "Subadministrator".
+Using the FPP protocoll this module logs in to the FirstClass server and issuess batch admin commands.
+Batch admin command can only be issued in the context of a user with subadministrative privileges.
+
+Default account name is "fcMoodle".
+
+
+3. Check that the FPP protocoll is working by running a Telnet session. If everyting is working you
+should get a "+0" answer from the server. 
+
+> telnet yourhost.domain.com 3333
++0
+
+Check that the "fcMoodle" is working by entering the following sequens of commands:
+
+> telnet yourhost.domain.com 3333
++0
+fcMoodle
++0
+
+the_password_you_gave_fcmoodle
++0
+
+Get user some_user_id 1201
+
+1201 0 some_user_id
++0
+
+
+
+4. On the Moodle host go to the directory where you have installed Moodle.
+Open the folder "auth", where all other authentication modules are installed,
+ and create a new directory with the name "fc". 
+
+Copy the files "config.html", "fcFPP.php" and "lib.php" to the "auth" directory.
+
+Now you need to add som strings to the language file. This distribution contains
+string for the English (en) and Swedish (sv) translation.
+
+Open the file "auth.php" in the folder "lang/sv" and paste the text from the file
+"auth.php - sv.txt" at the end of the file above the line "?>"
+
+Open the file "auth.php" in the folder "lang/en" and paste the text from the file
+"auth.php - en.txt" at the end of the file above the line "?>"
+
+
+
+
+
+
+
+
+
+
index daac9b5..99cec42 100644 (file)
-<?php\r
-/************************************************************************/\r
-/* fcFPP: Php class for FirstClass Flexible Provisining Protocol        */\r
-/* =============================================================        */\r
-/*                                                                      */\r
-/* Copyright (c) 2004 SKERIA Utveckling, Teknous                        */\r
-/* http://skeria.skelleftea.se                                          */\r
-/*                                                                      */\r
-/* Flexible Provisioning Protocol is a real-time, IP based protocol     */\r
-/* which provides direct access to the scriptable remote administration */\r
-/* subsystem of the core FirstClass Server. Using FPP, it is possible to*/\r
-/* implement automated provisioning and administration systems for      */\r
-/* FirstClass, avoiding the need for a point and click GUI. FPP can also*/\r
-/* be used to integrate FirstClass components into a larger unified     */\r
-/* system.                                                              */\r
-/*                                                                      */\r
-/* This program is free software. You can redistribute it and/or modify */\r
-/* it under the terms of the GNU General Public License as published by */\r
-/* the Free Software Foundation; either version 2 of the License.       */\r
-/************************************************************************/\r
-/* Author: Torsten Anderson, torsten.anderson@skeria.skelleftea.se\r
- */\r
-\r
-class fcFPP\r
-{    \r
-    var $_hostname;         // hostname of FirstClass server we are connection to\r
-    var $_port;             // port on which fpp is running\r
-    var $_conn = 0;         // socket we are connecting on\r
-    var $_debug = FALSE;    // set to true to see some debug info\r
-    \r
-    // class constructor\r
-    function fcFPP($host="localhost", $port="3333")\r
-    {\r
-       $this->_hostname = $host;\r
-       $this->_port = $port;\r
-       $this->_user = "";\r
-       $this->_pwd = "";  \r
-    }\r
-    \r
-    // open a connection to the FirstClass server\r
-    function open()\r
-    {\r
-       if($this->_debug) echo "Connecting to host ";\r
-       $host = $this->_hostname;\r
-       $port = $this->_port;\r
-\r
-       if($this->_debug) echo "[$host:$port]..";\r
-\r
-       // open the connection to the FirstClass server\r
-       $conn = fsockopen($host, $port, $errno, $errstr, 5);\r
-       if(!$conn)\r
-       {\r
-           echo "connection failed!".$errno. $errstr;\r
-           return false;\r
-       }\r
-       \r
-       // We are connected\r
-       if($this->_debug) echo "connected!";\r
-       \r
-       // Read connection message.\r
-       $line = fgets ($conn);        //+0\r
-       $line = fgets ($conn);        //new line\r
-\r
-       // store the connection in this class, so we can use it later\r
-       $this->_conn = & $conn;\r
-\r
-       return true;\r
-    }\r
-\r
-    // close any open connections\r
-    function close()\r
-    {        \r
-       // get the current connection\r
-       $conn = &$this->_conn;\r
-\r
-       // close it if it's open\r
-       if($conn)\r
-       {\r
-           fclose($conn);\r
-\r
-           // cleanup the variable\r
-           unset($this->_conn);\r
-           return true;\r
-       }\r
-       return;\r
-    }\r
-    \r
-    \r
-    // Authenticate to the FirstClass server\r
-    function login($userid, $passwd)\r
-    {\r
-       // we did have a connection right?!\r
-        if($this->_conn)\r
-       {\r
-           # Send username\r
-           fputs($this->_conn,"$userid\r\n");\r
-\r
-           $line = fgets ($this->_conn);        //new line\r
-           $line = fgets ($this->_conn);        //+0\r
-           $line = fgets ($this->_conn);        //new line\r
-    \r
-           # Send password\r
-           fputs($this->_conn,"$passwd\r\n");\r
-           $line = fgets ($this->_conn);        //new line\r
-           $line = fgets ($this->_conn);        //+0\r
-           $line = fgets ($this->_conn);        //+0 or message\r
-           \r
-           if($this->_debug) echo $line;\r
-           \r
-           if (preg_match ("/^\+0/", $line)) {         //+0, user with subadmin privileges\r
-               $this->_user = $userid;\r
-               $this->_pwd  = $passwd; \r
-               return TRUE;            \r
-           } elseif (preg_match ("/^\Sorry/",$line)){  //Denied access but a valid user and password\r
-               return TRUE;\r
-           } else {                                    //Invalid user or password\r
-               return FALSE;\r
-           }\r
-    \r
-\r
-       }\r
-       return FALSE;\r
-    }\r
-\r
-    // Get the list of groups the user is a member of \r
-    function getGroups($userid){\r
-       \r
-       $groups = array();\r
-       \r
-       // we must be logged in as a user with subadmin privileges \r
-       if($this->_conn AND $this->_user) {\r
-           # Send BA-command to get groups\r
-           fputs($this->_conn,"GET USER '" . $userid . "' 4 -1\r");\r
-           $line = "";\r
-           while (!$line) {\r
-               $line = trim(fgets ($this->_conn));\r
-           }\r
-           $n = 0;\r
-           while ($line AND !preg_match("/^\+0/", $line) AND $line != "-1003") {\r
-               list( , , $groups[$n++]) = explode(" ",$line,3);\r
-               $line = trim(fgets ($this->_conn));\r
-           }\r
-            if($this->_debug) echo "getGroups:" . implode(",",$groups);\r
-       }\r
-       \r
-       return $groups;\r
-    }\r
-\r
-    // Check if the user is member of any of the groups.\r
-    // Return the list of groups the user is member of.\r
-    function isMemberOf($userid, $groups){\r
-       \r
-       $usergroups = array_map("strtolower",$this->getGroups($userid));\r
-       $groups = array_map("strtolower",$groups);\r
-       \r
-       $result = array_intersect($groups,$usergroups);\r
-       \r
-        if($this->_debug) echo "isMemberOf:" . implode(",",$result);\r
-       \r
-       return $result;\r
-\r
-    }\r
-    \r
-    function getUserInfo($userid, $field){\r
-       \r
-       $userinfo = "";\r
-       \r
-       if($this->_conn AND $this->_user) {\r
-           # Send BA-command to get data\r
-           fputs($this->_conn,"GET USER '" . $userid . "' " . $field . "\r");\r
-           $line = "";\r
-           while (!$line) {\r
-               $line = trim(fgets ($this->_conn));\r
-           }\r
-           $n = 0;\r
-           while ($line AND !preg_match("/^\+0/", $line)) {\r
-               list( , , $userinfo) = explode(" ",$line,3);\r
-               $line = trim(fgets ($this->_conn));\r
-           }\r
-           if($this->_debug) echo "getUserInfo:" . $userinfo;\r
-       }\r
-         \r
-       return str_replace('\r',' ',trim($userinfo,'"'));\r
-\r
-    }\r
-\r
-    function getResume($userid){\r
-       \r
-       $resume = "";\r
-\r
-       $pattern = "/\[.+:.+\..+\]/";         // Remove references to pictures in resumes\r
-       \r
-       if($this->_conn AND $this->_user) {\r
-           # Send BA-command to get data\r
-           fputs($this->_conn,"GET RESUME '" . $userid . "' 6\r");\r
-           $line = "";\r
-           while (!$line) {\r
-               $line = trim(fgets ($this->_conn));\r
-           }\r
-           $n = 0;\r
-           while ($line AND !preg_match("/^\+0/", $line)) {\r
-               $resume .= preg_replace($pattern,"",str_replace('\r',"\n",trim($line,'6 ')));\r
-               $line = trim(fgets ($this->_conn));\r
-               //print $line;\r
-               \r
-           }\r
-           if($this->_debug) echo "getResume:" . $resume;\r
-       }\r
-         \r
-       return $resume;\r
-\r
-    }\r
-    \r
-    \r
-}\r
-   \r
-\r
+<?php
+/************************************************************************/
+/* fcFPP: Php class for FirstClass Flexible Provisining Protocol        */
+/* =============================================================        */
+/*                                                                      */
+/* Copyright (c) 2004 SKERIA Utveckling, Teknous                        */
+/* http://skeria.skelleftea.se                                          */
+/*                                                                      */
+/* Flexible Provisioning Protocol is a real-time, IP based protocol     */
+/* which provides direct access to the scriptable remote administration */
+/* subsystem of the core FirstClass Server. Using FPP, it is possible to*/
+/* implement automated provisioning and administration systems for      */
+/* FirstClass, avoiding the need for a point and click GUI. FPP can also*/
+/* be used to integrate FirstClass components into a larger unified     */
+/* system.                                                              */
+/*                                                                      */
+/* This program is free software. You can redistribute it and/or modify */
+/* it under the terms of the GNU General Public License as published by */
+/* the Free Software Foundation; either version 2 of the License.       */
+/************************************************************************/
+/* Author: Torsten Anderson, torsten.anderson@skeria.skelleftea.se
+ */
+
+class fcFPP
+{    
+    var $_hostname;         // hostname of FirstClass server we are connection to
+    var $_port;             // port on which fpp is running
+    var $_conn = 0;         // socket we are connecting on
+    var $_debug = FALSE;    // set to true to see some debug info
+    
+    // class constructor
+    function fcFPP($host="localhost", $port="3333")
+    {
+       $this->_hostname = $host;
+       $this->_port = $port;
+       $this->_user = "";
+       $this->_pwd = "";  
+    }
+    
+    // open a connection to the FirstClass server
+    function open()
+    {
+       if($this->_debug) echo "Connecting to host ";
+       $host = $this->_hostname;
+       $port = $this->_port;
+
+       if($this->_debug) echo "[$host:$port]..";
+
+       // open the connection to the FirstClass server
+       $conn = fsockopen($host, $port, $errno, $errstr, 5);
+       if(!$conn)
+       {
+           echo "connection failed!".$errno. $errstr;
+           return false;
+       }
+       
+       // We are connected
+       if($this->_debug) echo "connected!";
+       
+       // Read connection message.
+       $line = fgets ($conn);        //+0
+       $line = fgets ($conn);        //new line
+
+       // store the connection in this class, so we can use it later
+       $this->_conn = & $conn;
+
+       return true;
+    }
+
+    // close any open connections
+    function close()
+    {        
+       // get the current connection
+       $conn = &$this->_conn;
+
+       // close it if it's open
+       if($conn)
+       {
+           fclose($conn);
+
+           // cleanup the variable
+           unset($this->_conn);
+           return true;
+       }
+       return;
+    }
+    
+    
+    // Authenticate to the FirstClass server
+    function login($userid, $passwd)
+    {
+       // we did have a connection right?!
+        if($this->_conn)
+       {
+           # Send username
+           fputs($this->_conn,"$userid\r\n");
+
+           $line = fgets ($this->_conn);        //new line
+           $line = fgets ($this->_conn);        //+0
+           $line = fgets ($this->_conn);        //new line
+    
+           # Send password
+           fputs($this->_conn,"$passwd\r\n");
+           $line = fgets ($this->_conn);        //new line
+           $line = fgets ($this->_conn);        //+0
+           $line = fgets ($this->_conn);        //+0 or message
+           
+           if($this->_debug) echo $line;
+           
+           if (preg_match ("/^\+0/", $line)) {         //+0, user with subadmin privileges
+               $this->_user = $userid;
+               $this->_pwd  = $passwd; 
+               return TRUE;            
+           } elseif (preg_match ("/^\Sorry/",$line)){  //Denied access but a valid user and password
+               return TRUE;
+           } else {                                    //Invalid user or password
+               return FALSE;
+           }
+    
+
+       }
+       return FALSE;
+    }
+
+    // Get the list of groups the user is a member of 
+    function getGroups($userid){
+       
+       $groups = array();
+       
+       // we must be logged in as a user with subadmin privileges 
+       if($this->_conn AND $this->_user) {
+           # Send BA-command to get groups
+           fputs($this->_conn,"GET USER '" . $userid . "' 4 -1\r");
+           $line = "";
+           while (!$line) {
+               $line = trim(fgets ($this->_conn));
+           }
+           $n = 0;
+           while ($line AND !preg_match("/^\+0/", $line) AND $line != "-1003") {
+               list( , , $groups[$n++]) = explode(" ",$line,3);
+               $line = trim(fgets ($this->_conn));
+           }
+            if($this->_debug) echo "getGroups:" . implode(",",$groups);
+       }
+       
+       return $groups;
+    }
+
+    // Check if the user is member of any of the groups.
+    // Return the list of groups the user is member of.
+    function isMemberOf($userid, $groups){
+       
+       $usergroups = array_map("strtolower",$this->getGroups($userid));
+       $groups = array_map("strtolower",$groups);
+       
+       $result = array_intersect($groups,$usergroups);
+       
+        if($this->_debug) echo "isMemberOf:" . implode(",",$result);
+       
+       return $result;
+
+    }
+    
+    function getUserInfo($userid, $field){
+       
+       $userinfo = "";
+       
+       if($this->_conn AND $this->_user) {
+           # Send BA-command to get data
+           fputs($this->_conn,"GET USER '" . $userid . "' " . $field . "\r");
+           $line = "";
+           while (!$line) {
+               $line = trim(fgets ($this->_conn));
+           }
+           $n = 0;
+           while ($line AND !preg_match("/^\+0/", $line)) {
+               list( , , $userinfo) = explode(" ",$line,3);
+               $line = trim(fgets ($this->_conn));
+           }
+           if($this->_debug) echo "getUserInfo:" . $userinfo;
+       }
+         
+       return str_replace('\r',' ',trim($userinfo,'"'));
+
+    }
+
+    function getResume($userid){
+       
+       $resume = "";
+
+       $pattern = "/\[.+:.+\..+\]/";         // Remove references to pictures in resumes
+       
+       if($this->_conn AND $this->_user) {
+           # Send BA-command to get data
+           fputs($this->_conn,"GET RESUME '" . $userid . "' 6\r");
+           $line = "";
+           while (!$line) {
+               $line = trim(fgets ($this->_conn));
+           }
+           $n = 0;
+           while ($line AND !preg_match("/^\+0/", $line)) {
+               $resume .= preg_replace($pattern,"",str_replace('\r',"\n",trim($line,'6 ')));
+               $line = trim(fgets ($this->_conn));
+               //print $line;
+               
+           }
+           if($this->_debug) echo "getResume:" . $resume;
+       }
+         
+       return $resume;
+
+    }
+    
+    
+}
+   
+
 ?>
\ No newline at end of file
index 4c2bd2d..70bedab 100644 (file)
-<?php  // $Id$\r
-       \r
-// FirstClass authentication using FirstClass Flexible Provisining Protocol\r
-\r
-/* Author: Torsten Anderson, torsten.anderson@skeria.skelleftea.se\r
-\r
-CHANGELOG\r
-\r
-README\r
-  Module will authenticate user against FirstClass server and check if user belongs to any of\r
-  the defined creator groups.\r
-  User authenticates using their existing FirstClass username and password.\r
-  Where possible userdata is copied from the FirstClass directory to Moodle. You may\r
-  want to modify this.\r
-  Module requires the fcFPP class to do it's jobb.\r
- */\r
-       \r
-\r
-require('fcFPP.php');\r
-   \r
-\r
-function auth_user_login ($username, $password) {\r
-/// Returns true if the username and password work\r
-/// and false if they don't\r
-\r
-    global $CFG;\r
-\r
-    $hostname = $CFG->auth_fchost;\r
-    $port     = $CFG->auth_fcfppport;\r
-\r
-    $retval = FALSE;\r
-\r
-    if (!$username or !$password) {    // Don't allow blank usernames or passwords\r
-        return $retval;\r
-    }\r
-\r
-\r
-    $fpp = new fcFPP($hostname,$port);\r
-    if ($fpp->open()) {\r
-       if ($fpp->login($username,$password)){\r
-          $retval = TRUE;\r
-       }\r
-    }\r
-    $fpp->close();\r
-\r
-    return $retval;\r
\r
-\r
-}\r
-\r
-function auth_get_userinfo($username){\r
-// Get user information from FirstCLass server and return it in an array.\r
-// Localize this routine to fit your needs. \r
-\r
-/*\r
-Moodle                FirstCLass fieldID in UserInfo form\r
-------                -----------------------------------\r
-firstname             1202\r
-lastname              1204\r
-email                 1252\r
-icq                   -\r
-phone1                1206\r
-phone2                1207 (Fax)\r
-institution           -  \r
-department            - \r
-address               1205\r
-city                  - \r
-country               -\r
-lang                  -\r
-timezone              8030 (Not used yet. Need to figure out how FC codes timezones)\r
-\r
-description           Get data from users resume. Pictures will be removed.\r
-\r
-*/\r
-\r
-    global $CFG;\r
-    \r
-    $hostname = $CFG->auth_fchost;\r
-    $port     = $CFG->auth_fcfppport;\r
-    $userid   = $CFG->auth_fcuserid;\r
-    $passwd   = $CFG->auth_fcpasswd; \r
-\r
-    $userinfo = array();\r
-\r
-    $fpp = new fcFPP($hostname,$port);\r
-    if ($fpp->open()) {\r
-       if ($fpp->login($userid,$passwd)){\r
-\r
-          $userinfo['firstname']   = $fpp->getUserInfo($username,"1202");\r
-          $userinfo['lastname']    = $fpp->getUserInfo($username,"1204");\r
-          $userinfo['email']       = strtok($fpp->getUserInfo($username,"1252"),',');\r
-          $userinfo['phone1']      = $fpp->getUserInfo($username,"1206");\r
-          $userinfo['phone2']      = $fpp->getUserInfo($username,"1207");\r
-          $userinfo['description'] = $fpp->getResume($username);\r
-\r
-       }\r
-    }\r
-\r
-    $fpp->close();\r
-\r
-    foreach($userinfo as $key => $value) {\r
-       if (!$value) {\r
-          unset($userinfo[$key]);\r
-       }\r
-    }\r
-    \r
-    return $userinfo;\r
-\r
-}\r
-\r
-\r
-function auth_iscreator($username=0) {\r
-//Get users group membership from the FirstClass server user and check if\r
-// user is member of one of the groups of creators.\r
-\r
-    global $CFG, $USER;\r
-\r
-    if (! $CFG->auth_fccreators) {\r
-       return false;\r
-    }\r
-\r
-    if (! $username) {\r
-       $username=$USER->username;\r
-    }\r
-\r
-    $fcgroups = array();\r
-\r
-    $hostname = $CFG->auth_fchost;\r
-    $port     = $CFG->auth_fcfppport;\r
-    $userid   = $CFG->auth_fcuserid;\r
-    $passwd   = $CFG->auth_fcpasswd; \r
-\r
-    $fpp = new fcFPP($hostname,$port);\r
-    if ($fpp->open()) {\r
-       if ($fpp->login($userid,$passwd)){\r
-          $fcgroups = $fpp->getGroups($username);\r
-       }\r
-    }\r
-    $fpp->close();\r
-\r
-   \r
-    if ((! $fcgroups)) {\r
-      return false;\r
-    }\r
-\r
-    $creators = explode(";",$CFG->auth_fccreators);\r
-   \r
-    foreach($creators as $creator) {\r
-        If (in_array($creator, $fcgroups)) return true;\r
-    }\r
-    \r
-    return false;\r
-}\r
-  \r
+<?php  // $Id$
+       
+// FirstClass authentication using FirstClass Flexible Provisining Protocol
+
+/* Author: Torsten Anderson, torsten.anderson@skeria.skelleftea.se
+
+CHANGELOG
+
+README
+  Module will authenticate user against FirstClass server and check if user belongs to any of
+  the defined creator groups.
+  User authenticates using their existing FirstClass username and password.
+  Where possible userdata is copied from the FirstClass directory to Moodle. You may
+  want to modify this.
+  Module requires the fcFPP class to do it's jobb.
+ */
+       
+
+require('fcFPP.php');
+   
+
+function auth_user_login ($username, $password) {
+/// Returns true if the username and password work
+/// and false if they don't
+
+    global $CFG;
+
+    $hostname = $CFG->auth_fchost;
+    $port     = $CFG->auth_fcfppport;
+
+    $retval = FALSE;
+
+    if (!$username or !$password) {    // Don't allow blank usernames or passwords
+        return $retval;
+    }
+
+
+    $fpp = new fcFPP($hostname,$port);
+    if ($fpp->open()) {
+       if ($fpp->login($username,$password)){
+          $retval = TRUE;
+       }
+    }
+    $fpp->close();
+
+    return $retval;
+
+}
+
+function auth_get_userinfo($username){
+// Get user information from FirstCLass server and return it in an array.
+// Localize this routine to fit your needs. 
+
+/*
+Moodle                FirstCLass fieldID in UserInfo form
+------                -----------------------------------
+firstname             1202
+lastname              1204
+email                 1252
+icq                   -
+phone1                1206
+phone2                1207 (Fax)
+institution           -  
+department            - 
+address               1205
+city                  - 
+country               -
+lang                  -
+timezone              8030 (Not used yet. Need to figure out how FC codes timezones)
+
+description           Get data from users resume. Pictures will be removed.
+
+*/
+
+    global $CFG;
+    
+    $hostname = $CFG->auth_fchost;
+    $port     = $CFG->auth_fcfppport;
+    $userid   = $CFG->auth_fcuserid;
+    $passwd   = $CFG->auth_fcpasswd; 
+
+    $userinfo = array();
+
+    $fpp = new fcFPP($hostname,$port);
+    if ($fpp->open()) {
+       if ($fpp->login($userid,$passwd)){
+
+          $userinfo['firstname']   = $fpp->getUserInfo($username,"1202");
+          $userinfo['lastname']    = $fpp->getUserInfo($username,"1204");
+          $userinfo['email']       = strtok($fpp->getUserInfo($username,"1252"),',');
+          $userinfo['phone1']      = $fpp->getUserInfo($username,"1206");
+          $userinfo['phone2']      = $fpp->getUserInfo($username,"1207");
+          $userinfo['description'] = $fpp->getResume($username);
+
+       }
+    }
+
+    $fpp->close();
+
+    foreach($userinfo as $key => $value) {
+       if (!$value) {
+          unset($userinfo[$key]);
+       }
+    }
+    
+    return $userinfo;
+
+}
+
+
+function auth_iscreator($username=0) {
+//Get users group membership from the FirstClass server user and check if
+// user is member of one of the groups of creators.
+
+    global $CFG, $USER;
+
+    if (! $CFG->auth_fccreators) {
+       return false;
+    }
+
+    if (! $username) {
+       $username=$USER->username;
+    }
+
+    $fcgroups = array();
+
+    $hostname = $CFG->auth_fchost;
+    $port     = $CFG->auth_fcfppport;
+    $userid   = $CFG->auth_fcuserid;
+    $passwd   = $CFG->auth_fcpasswd; 
+
+    $fpp = new fcFPP($hostname,$port);
+    if ($fpp->open()) {
+       if ($fpp->login($userid,$passwd)){
+          $fcgroups = $fpp->getGroups($username);
+       }
+    }
+    $fpp->close();
+
+   
+    if ((! $fcgroups)) {
+      return false;
+    }
+
+    $creators = explode(";",$CFG->auth_fccreators);
+   
+    foreach($creators as $creator) {
+        If (in_array($creator, $fcgroups)) return true;
+    }
+    
+    return false;
+}
+  
index 9783aa3..3bd8930 100644 (file)
@@ -1,23 +1,23 @@
-Moodle Language Packs\r
-\r
-This directory contains the standard packaged Moodle language files,\r
-for making the Moodle interface appear in different interfaces.\r
-\r
-The default language for Moodle is the English language, under the \r
-Unicode scheme (UTF8).\r
-\r
-To add more languages to Moodle, you can either:\r
-\r
- 1) use the Moodle languages GUI in the interface to fetch \r
-    new languages and install them in your 'dataroot' directory.\r
-\r
- 2) download them and unzip the packs in this directory manually\r
-\r
-\r
-For more information, see the Moodle Documentation:\r
-\r
-   http://docs.moodle.org/en/Translation\r
-\r
-\r
-Cheers,\r
-Moodle Development Team\r
+Moodle Language Packs
+
+This directory contains the standard packaged Moodle language files,
+for making the Moodle interface appear in different interfaces.
+
+The default language for Moodle is the English language, under the 
+Unicode scheme (UTF8).
+
+To add more languages to Moodle, you can either:
+
+ 1) use the Moodle languages GUI in the interface to fetch 
+    new languages and install them in your 'dataroot' directory.
+
+ 2) download them and unzip the packs in this directory manually
+
+
+For more information, see the Moodle Documentation:
+
+   http://docs.moodle.org/en/Translation
+
+
+Cheers,
+Moodle Development Team
index b915845..879670a 100644 (file)
@@ -1,10 +1,10 @@
-<p align="center"><b>Quick Grade</b></p>\r
-\r
-<p>With quickgrading enabled you can quickly grade multiple assignments on one page.</p>\r
-\r
-<p>Just change the grades and comments and use the Save button at the bottom to save \r
-   all your changes for that page at once.</p>\r
-\r
-<p>The normal grading buttons on the right still work too in case you need more space.  \r
-   Your quickgrading preference is saved and will apply to all assignments in all courses.</p>\r
-\r
+<p align="center"><b>Quick Grade</b></p>
+
+<p>With quickgrading enabled you can quickly grade multiple assignments on one page.</p>
+
+<p>Just change the grades and comments and use the Save button at the bottom to save 
+   all your changes for that page at once.</p>
+
+<p>The normal grading buttons on the right still work too in case you need more space.  
+   Your quickgrading preference is saved and will apply to all assignments in all courses.</p>
+
index f3595dd..a2bfd24 100644 (file)
@@ -1,18 +1,18 @@
-<p align="center"><b>Import PowerPoint HTML</b></p>\r
-<p> HOW TO USE</p>\r
-<p>All of the PowerPoint slides get imported as Branch Tables with Previous and Next answers.</p>\r
-<p>\r
-<ol>\r
-<li>Open up your PowerPoint presentation.</li>\r
-<li>Save it As a Web Page (no special options)</li>\r
-<li>The result of step 3 should be a htm file and a folder with all of the slides converted to web pages.<br />\r
-  ZIP THE FOLDER only.</li>\r
-<li>Go to your moodle site and add a new lesson.</li>\r
-<li>After saving the lesson settings you should see 4 options under &quot;What would you like to do first?&quot; Click on &quot;Import PowerPoint&quot;</li>\r
-<li>Use to the &quot;Browse...&quot; button to find your zip file from step 3. Then click on &quot;Upload this file&quot;</li>\r
-<li>If everything worked, the next screen should just display a continue button.</li>\r
-</ol>\r
-</p>\r
-<p>If any images were in your PowerPoint, they would have been saved as course files in moddata/XY where X is your lesson's name and Y is a number (usually 0). Also, during the import process, files are created in your moodle data directory inside temp/lesson. These files are not deleted by importppt.php as of yet.</p>\r
-<p align="center">&nbsp;</p>\r
-\r
+<p align="center"><b>Import PowerPoint HTML</b></p>
+<p> HOW TO USE</p>
+<p>All of the PowerPoint slides get imported as Branch Tables with Previous and Next answers.</p>
+<p>
+<ol>
+<li>Open up your PowerPoint presentation.</li>
+<li>Save it As a Web Page (no special options)</li>
+<li>The result of step 3 should be a htm file and a folder with all of the slides converted to web pages.<br />
+  ZIP THE FOLDER only.</li>
+<li>Go to your moodle site and add a new lesson.</li>
+<li>After saving the lesson settings you should see 4 options under &quot;What would you like to do first?&quot; Click on &quot;Import PowerPoint&quot;</li>
+<li>Use to the &quot;Browse...&quot; button to find your zip file from step 3. Then click on &quot;Upload this file&quot;</li>
+<li>If everything worked, the next screen should just display a continue button.</li>
+</ol>
+</p>
+<p>If any images were in your PowerPoint, they would have been saved as course files in moddata/XY where X is your lesson's name and Y is a number (usually 0). Also, during the import process, files are created in your moodle data directory inside temp/lesson. These files are not deleted by importppt.php as of yet.</p>
+<p align="center">&nbsp;</p>
+
index 0b5714d..ae15a80 100644 (file)
@@ -1,28 +1,28 @@
-<p align="center"><b>Question Option</b></p>\r
-\r
-<p>A few of the Question Types have an option which is activated by clicking on\r
-    the checkbox. The question types and the meaning of the options are \r
-    detailed below.</p>\r
-\r
-<ol>\r
-<li><p><b>Multichoice</b> There is variant of Multichoice questions called \r
-    <b>&quot;Multichoice Multianswer&quot;</b> questions. If the Question \r
-    Option is selected then the student is required to select all the \r
-    correct answers from the set of answers. The question may or may not tell \r
-    the student <i>how many</i> correct answers there are. For example &quot;Which of the \r
-    following were US Presidents?&quot; does not, while "Select the two US \r
-    presidents from the following list." does. The actual number of correct \r
-    answers can be from <b>one</b> up to the number of choices. (A Multichoice \r
-    Multianswer question with one correct answer <b>is</b> different from a \r
-    Multichoice question as the former allows the student the possibility of \r
-    choosing more than one answer while the latter does not.)</p></li>\r
-\r
-<li>\r
-  <p><b>Short Answer</b> There are two different comparison systems available \r
-      for the Short Answer type of question: the simple system is used by default; \r
-      the &quot;Regular Expressions&quot; system is used if the &quot;Use Regular \r
-      Expressions&quot; option box is checked.  For more information, please read\r
-      the Lesson question types help file.</p>\r
-</li>\r
-</ol>\r
-<p>The other Question Types do not use the Question Option.</p>\r
+<p align="center"><b>Question Option</b></p>
+
+<p>A few of the Question Types have an option which is activated by clicking on
+    the checkbox. The question types and the meaning of the options are 
+    detailed below.</p>
+
+<ol>
+<li><p><b>Multichoice</b> There is variant of Multichoice questions called 
+    <b>&quot;Multichoice Multianswer&quot;</b> questions. If the Question 
+    Option is selected then the student is required to select all the 
+    correct answers from the set of answers. The question may or may not tell 
+    the student <i>how many</i> correct answers there are. For example &quot;Which of the 
+    following were US Presidents?&quot; does not, while "Select the two US 
+    presidents from the following list." does. The actual number of correct 
+    answers can be from <b>one</b> up to the number of choices. (A Multichoice 
+    Multianswer question with one correct answer <b>is</b> different from a 
+    Multichoice question as the former allows the student the possibility of 
+    choosing more than one answer while the latter does not.)</p></li>
+
+<li>
+  <p><b>Short Answer</b> There are two different comparison systems available 
+      for the Short Answer type of question: the simple system is used by default; 
+      the &quot;Regular Expressions&quot; system is used if the &quot;Use Regular 
+      Expressions&quot; option box is checked.  For more information, please read
+      the Lesson question types help file.</p>
+</li>
+</ol>
+<p>The other Question Types do not use the Question Option.</p>
index 35772e4..3e32316 100644 (file)
-<p align="center"><b>Question Types</b></p>\r
-\r
-<p>The types of Questions currently supported by the Lesson module are:\r
-\r
-<ol>\r
-<li><p><b>Multichoice</b> This is the default question type. Multichoice questions\r
-    are popular questions where the student is asked to choose one answer from a\r
-    set of alternatives. The correct answer takes the student further into the\r
-    lesson, the wrong answers do not. The wrong answers are sometimes called the\r
-    &quot;distractors&quot; and the utility of these questions often rely more\r
-    on the quality of the distractors than either the questions themselves or their\r
-    correct answers.</p>\r
-\r
-<p> Each answer can optionally have a response. If no response is\r
-    entered for an answer then the default response &quot;That's the Correct\r
-    Answer&quot; or &quot;That's the Wrong Answer&quot; is shown to the student.  </p>\r
-\r
-<p>It is possible to have more than one correct answer to a multichoice question.\r
-    The different correct answers may give the student different responses and\r
-    jump to different (forward) pages in the lesson but\r
-    do not vary in their grades, (that is, some answers are <b>not</b> more correct\r
-    than others, at least in terms of grade.) It is possible for all the answers\r
-    to be correct and they might take the student to different (forward) parts of\r
-    the lesson depending on which one is chosen.</p>\r
-\r
-<p>There is variant of Multichoice questions called <b>&quot;Multichoice\r
-    Multianswer&quot;</b> questions. These require the student to select all the\r
-    correct answers from the set of answers. The question may or may not tell\r
-    the student how many correct answers there are. For example &quot;Which of the\r
-    following were US Presidents?&quot; does not, while "Select the two US\r
-    presidents from the following list." does. The actual number of correct\r
-    answers can be from <b>one</b> up to the number of choices. (A Multichoice\r
-    Multianswer question with one correct answer <b>is</b> different from a\r
-    Multichoice question as the former allows the student the possibility of\r
-    choosing more than one answer while the latter does not.)</p>\r
-\r
-<p>Again the correct answers are flagged using forward jumps, the wrong answers\r
-    by same page or backward jumps. When there is more than one correct answer\r
-    the jumps should all go to the same page, similarly with the wrong answers.\r
-    If that is <b>not</b> the case a warning is given on the teacher's view of\r
-    the lesson. The correct response, if required, should be given on the first\r
-    correct answer and the wrong response, if required, should be on the first\r
-  wrong answer. Responses on the other answers are ignored (without warning).  </p></li>\r
-\r
-<li><p><b>Short Answer</b> </p>\r
-  <p>The student is prompted for a short piece of text.\r
-    This is checked against one or more answers. Answers can be either correct\r
-    or wrong. Each answer can optionally have a response. If no response is\r
-    entered for an answer then the default response &quot;That's the Correct\r
-    Answer&quot; or &quot;That's the Wrong Answer&quot; is shown to the student.\r
-    If the text entered does not match any of the answers the question is wrong\r
-    and the student is shown the default wrong response.</p>\r
-  <p><strong>There are two different comparison systems</strong> available for the \r
-      Short Answer type of question: the simple system is used by default; the \r
-      &quot;Regular Expressions&quot; system is used if the &quot;Use Regular \r
-      Expressions&quot; option box is checked. </p>\r
-  <ul>\r
-    <li><strong>Simple analysis</strong>\r
-      <p>In this (default) system of analysis, the comparisons ignore the case of the text. The \r
-        asterisk (*) character can be used in answers as a &quot;wild card&quot;\r
-        character. It stands for any number of characters (including no characters\r
-        at all). For example, the answer &quot;Long*&quot; will match\r
-        &quot;longer&quot;, &quot;longest&quot; and &quot;long&quot;. If one of\r
-        the answers is just &quot;*&quot; (a single *) this answer will match\r
-        anything, it is normally used as the last &quot;catch-all&quot; answer. The\r
-        matching process goes through the answers in the order they appear on the\r
-        screen. Once a match is found the process stops and the corresponding\r
-        result (and response, if present) is returned. So, if for example the\r
-        answers are Longest, Long* and * (in that order), the input\r
-        &quot;longer&quot; will match the second answer and, in this case, the\r
-        third answer, although a match, is ignored.</p>\r
-      <p> If an asterisk (*) is actually needed in an answer, it should be entered as\r
-        \*, backslash asterisk.</p>\r
-    </li>\r
-  </ul>\r
-  <ul>\r
-    <li><strong>Regular Expressions analysis</strong>\r
-      <p>This system gives you access to a more powerful but more complicated system for \r
-          analysing the student's answers. For a complete introduction to Regular Expressions, \r
-          see these sites <a href="http://www.zend.com/zend/tut/tutorial-delin2.php" target="_blank">regular-expressions \r
-          tutorial</a> or <a href="http://perso.wanadoo.fr/joseph.rezeau/eao/developpement/expandRegexpToString.htm#" \r
-          target="_blank">rezeau.org</a>. </p>\r
-      <h3>Correct answer matching a regular expression pattern </h3>\r
-      <p>It is not possible to give complete examples of the vast possibilities offered \r
-          by this system, and the following are just some possibilities. </p>\r
-      <p><strong>Example 1.</strong> Suppose your question is &quot;What are the colors \r
-          of the French flag?&quot;. In the Answer 1 frame you type this regular \r
-          expression: &quot;<span class="c_computeroutput">it&rsquo;s blue, white(,| and) \r
-          red</span>/i&quot;. This will match any of those four student answers:</p>\r
-      <ul>\r
-        <li>it&rsquo;s blue, white, red</li>\r
-        <li>it&rsquo;s blue, white and red</li>\r
-        <li>It&rsquo;s blue, white, red</li>\r
-        <li>It&rsquo;s blue, white and red </li>\r
-      </ul>\r
-      <p>Please note that by default a regular expression match is case sensitive; to \r
-          make the match case insensitive you must add the <strong>/i</strong> parameter \r
-          right at the end of your expression.</p>\r
-      <p><strong>Example 2</strong>. Question: &quot;What is blue, or red, or yellow?&quot;. \r
-          Answer: &quot;(|it's )a colou?r&quot;. This will match:</p>\r
-      <ul>\r
-        <li>a colour</li>\r
-        <li> a color</li>\r
-        <li>it's a colour</li>\r
-        <li>it's a color</li>\r
-      </ul>\r
-      <p>Notes.- The beginning of this regular expression &quot;(|it's )&quot; will \r
-          match either nothing or &quot;it's  &quot; (i.e. &quot;it's&quot; followed by \r
-          a space). The ? (question-mark) means: preceding character zero or one time; \r
-          it is used here to match British English as well as US spelling.</p>\r
-      <p><strong>Example 3.</strong> Question: &quot;Name an animal whose name is made \r
-          of 3 letters and the middle letter is the vowel <em>a</em>&quot;. Anwer: \r
-          &quot;[bcr]at&quot;. This will match: bat, cat and rat. </p>\r
-      <h3>Detecting missing required words or character strings</h3>\r
-      <p>Regular expressions alone cannot detect absent character strings, so you have to \r
-          add a little code in your Answer to take care of this. Any Teacher Answer which \r
-          begins with a double hyphen will analyse the student&rsquo;s answer to find out \r
-          whether the following string is present or absent. If present, the analysis \r
-          continues to the next question; if absent, the analysis stops and the relevant \r
-          Response message is displayed.</p>\r
-      <p><strong>Example 4.  </strong></p>\r
-      <ul>\r
-        <li>Answer 2: <span class="c_computeroutput">--.*blue.*</span>/i</li>\r
-        <li>student answer: &quot;it's red and white&quot; </li>\r
-        <li>Response 2: <span class="c_computeroutput">The color of the sky is missing!</span></li>\r
-        <li>Jump 2: <span class="c_computeroutput">this page</span></li>\r
-      </ul>\r
-      <p>Here, the . (dot) stands for &ldquo;any character&rdquo; and the * (asterisk) \r
-          means &ldquo;preceding special character repeated any number of times&rdquo;. \r
-          The Answer2 regular expression above means: check whether the character string \r
-          &quot;blue&quot;, preceded with anything and followed by anything is absent \r
-          from the student's answer. Please note that the use of the asterisk is different \r
-          in the Simple analysis system and in the Regular Expressions system.</p>\r
-      <p><strong>Example 5.</strong> Question: &quot;Name an animal whose name is made of \r
-          3 letters and the middle letter is the vowel <em>a</em>&quot;. Teacher Answer: &quot;--[b|c|r]&quot;. Response: &quot;Your answer should start with one of these letters: b, c or r&quot; </p>\r
-      <h3>Detecting unwanted (incorrect) words or character strings</h3>\r
-      <p>You may want to detect, in the student's answer, the presence of one or several \r
-          words which should be <strong>not</strong> be there (because they are wrong) and \r
-          to single them out with a specific response. Just start your teacher Answer by a \r
-          double plus sign (++). </p>\r
-      <p><strong>Example 6. </strong></p>\r
-      <ul>\r
-        <li>Answer 3: ++(yellow|black|orange|green|black|pink)/i</li>\r
-        <li>student answer: &quot;it's blue, orange and white&quot; </li>\r
-        <li>Response 3: One or more colors are wrong!</li>\r
-        <li>Jump 3: this page</li></ul>\r
-        <p>If any of these (wrong) colors is detected in the student&rsquo;s answer, \r
-            then the negative feedback message (Response 3) will be displayed and the \r
-            wrong strings will be colored red (or the color of the .incorrect class if \r
-            it exists in a CSS stylesheet of your active theme).</p>\r
-      <p><strong>Example 7</strong>. Question: &quot;Name an animal whose name is made \r
-          of 3 letters and the middle letter is the vowel <em>a</em>&quot;. Teacher \r
-          Answer: &quot;++hat&quot;. Response: &quot;You might wear one made of an \r
-          animal's skin, but a hat can't be considered as an animal.&quot;   </p>\r
-      <h3>Escaping special characters </h3>\r
-      <p>If you need to use characters which are part of the regular expressions set \r
-          of <em>special characters</em>, you need to &quot;escape&quot; them (i.e. precede \r
-          them with a backslash). E.g. if you want to accept the answer &quot;My computer \r
-          cost 1000$&quot;, you must write the regular expression as &quot;My computer cost \r
-          1000\$&quot;. The special characters which must be escaped are .^$*()[]+?|</p>\r
-    </li>\r
-  </ul>\r
-</li>\r
-\r
-<li><p><b>True/False</b> The answer to this type of question only has two options,\r
-    true or false. The student is prompted to choose which is the correct\r
-    option. This type of question is basically a Multichoice question with just\r
-    two choices.</p></li>\r
-\r
-<li><p><b>Matching</b> These are quite powerful and flexible questions. They\r
-    consist of a list of names or statements which must be correctly matched\r
-    against other list of names or statements. For example &quot;Match the\r
-    Capital with the Country&quot; with the two lists Japan, Canada, Italy and\r
-    Tokyo, Ottawa, Rome. It is possible to have repeated entries in one of the\r
-    lists but care should be taken to make the repeats identical. For example\r
-    &quot;Identify the type of these creatures&quot; with the lists Sparrow,\r
-    Cow, Ant, Dog and Bird, Animal, Insect, Animal. </p>\r
-\r
-<p>When creating this type of question the items for the first list go into the\r
-    Answer boxes and items for the second list go into the Response boxes. Once\r
-    created a more sensible labeling scheme is shown. When the student\r
-    successfully matches the items the jump on the first answer is used. An\r
-    unsuccessful answer jumps to the page on the second answer. The question does\r
-    <b>not</b> support custom responses, the student is told how many matches\r
-    are correct or if all the matches are correct.</p>\r
-\r
-<p>Unlike the Multichoice question where the choices are shown in a random\r
-    order, the first list of items is <b>not</b> shuffled but shown in the same\r
-    order as entered. This allows for <b>&quot;Ordered&quot;</b> questions to be\r
-    constructed. Consider the question &quot; Put the following into the order\r
-    they were born, the earliest first&quot; with the lists 1., 2., 3., 4. and\r
-    Longfellow, Lawrence, Lowell, Larkin. The second list is shuffed before\r
-    being used in the question, of course.</p></li>\r
-\r
-<li><p><b>Numerical</b> This type of question requires a number as the answer.\r
-    In it's simplest form it requires just one answer to be specified. For\r
-    example &quot;What is 2 plus 2?&quot; with the answer 4 given a forward\r
-    jump. However, it is better to specify a range because the internal rounding\r
-    of numerical values can make single numeric comparisons rather hit or miss.\r
-    Thus, if the question were &quot;What is 10 divided by 3&quot; it would be\r
-    necessary to give the answer as <b>&quot;Minimum:Maximum&quot;</b>, that\r
-    is <b>two</b> values separated by a colon (:). Thus if 3.33:3.34 is given as the\r
-    acceptable range for the answer, then the answers 3.33, 3.333, 3.3333...\r
-    would all be taken as correct answers. &quot;Wrong&quot; answers would\r
-    include 3.3 (less than the minimum) and 3.4 (greater than the maximum).</p>\r
-\r
-<p>More than one correct answer is allowed and the answers can be either single\r
-    or pair of values. Note that the order in which the answers are tested is\r
-    Answer 1, Answer 2... so some care needs to taken if the desired response\r
-    is to appear. For example the question &quot;When was Larkin born?&quot;\r
-    could have the single value of 1922, the exact answer, and the pair of\r
-    values 1920:1929, the 20's, as the less exact answer.The order in which\r
-    these values should be tested is, obviously, 1922 then 1920:1929. The\r
-    first answer might have the response &quot;That's exactly right&quot;\r
-    while the other answer's response might be &quot;That's close, you've got\r
-    the right decade&quot;</p>\r
-\r
-<p>Wrong answers can be given but depending on their actual range, care should\r
-    be taken to place them after the correct answers. For example in adding the\r
-    wrong answer 3:4 to the &quot;10 divided by 3&quot; question it needs to come\r
-    after the correct answer. That is the answers are ordered 3.33:3.34 (the\r
-    &quot;correct&quot; answer) then 3:4 (the &quot;wrong&quot; answer, but\r
-    not wildly wrong answer!).</p></li>\r
-</ul>\r
-\r
+<p align="center"><b>Question Types</b></p>
+
+<p>The types of Questions currently supported by the Lesson module are:
+
+<ol>
+<li><p><b>Multichoice</b> This is the default question type. Multichoice questions
+    are popular questions where the student is asked to choose one answer from a
+    set of alternatives. The correct answer takes the student further into the
+    lesson, the wrong answers do not. The wrong answers are sometimes called the
+    &quot;distractors&quot; and the utility of these questions often rely more
+    on the quality of the distractors than either the questions themselves or their
+    correct answers.</p>
+
+<p> Each answer can optionally have a response. If no response is
+    entered for an answer then the default response &quot;That's the Correct
+    Answer&quot; or &quot;That's the Wrong Answer&quot; is shown to the student.  </p>
+
+<p>It is possible to have more than one correct answer to a multichoice question.
+    The different correct answers may give the student different responses and
+    jump to different (forward) pages in the lesson but
+    do not vary in their grades, (that is, some answers are <b>not</b> more correct
+    than others, at least in terms of grade.) It is possible for all the answers
+    to be correct and they might take the student to different (forward) parts of
+    the lesson depending on which one is chosen.</p>
+
+<p>There is variant of Multichoice questions called <b>&quot;Multichoice
+    Multianswer&quot;</b> questions. These require the student to select all the
+    correct answers from the set of answers. The question may or may not tell
+    the student how many correct answers there are. For example &quot;Which of the
+    following were US Presidents?&quot; does not, while "Select the two US
+    presidents from the following list." does. The actual number of correct
+    answers can be from <b>one</b> up to the number of choices. (A Multichoice
+    Multianswer question with one correct answer <b>is</b> different from a
+    Multichoice question as the former allows the student the possibility of
+    choosing more than one answer while the latter does not.)</p>
+
+<p>Again the correct answers are flagged using forward jumps, the wrong answers
+    by same page or backward jumps. When there is more than one correct answer
+    the jumps should all go to the same page, similarly with the wrong answers.
+    If that is <b>not</b> the case a warning is given on the teacher's view of
+    the lesson. The correct response, if required, should be given on the first
+    correct answer and the wrong response, if required, should be on the first
+  wrong answer. Responses on the other answers are ignored (without warning).  </p></li>
+
+<li><p><b>Short Answer</b> </p>
+  <p>The student is prompted for a short piece of text.
+    This is checked against one or more answers. Answers can be either correct
+    or wrong. Each answer can optionally have a response. If no response is
+    entered for an answer then the default response &quot;That's the Correct
+    Answer&quot; or &quot;That's the Wrong Answer&quot; is shown to the student.
+    If the text entered does not match any of the answers the question is wrong
+    and the student is shown the default wrong response.</p>
+  <p><strong>There are two different comparison systems</strong> available for the 
+      Short Answer type of question: the simple system is used by default; the 
+      &quot;Regular Expressions&quot; system is used if the &quot;Use Regular 
+      Expressions&quot; option box is checked. </p>
+  <ul>
+    <li><strong>Simple analysis</strong>
+      <p>In this (default) system of analysis, the comparisons ignore the case of the text. The 
+        asterisk (*) character can be used in answers as a &quot;wild card&quot;
+        character. It stands for any number of characters (including no characters
+        at all). For example, the answer &quot;Long*&quot; will match
+        &quot;longer&quot;, &quot;longest&quot; and &quot;long&quot;. If one of
+        the answers is just &quot;*&quot; (a single *) this answer will match
+        anything, it is normally used as the last &quot;catch-all&quot; answer. The
+        matching process goes through the answers in the order they appear on the
+        screen. Once a match is found the process stops and the corresponding
+        result (and response, if present) is returned. So, if for example the
+        answers are Longest, Long* and * (in that order), the input
+        &quot;longer&quot; will match the second answer and, in this case, the
+        third answer, although a match, is ignored.</p>
+      <p> If an asterisk (*) is actually needed in an answer, it should be entered as
+        \*, backslash asterisk.</p>
+    </li>
+  </ul>
+  <ul>
+    <li><strong>Regular Expressions analysis</strong>
+      <p>This system gives you access to a more powerful but more complicated system for 
+          analysing the student's answers. For a complete introduction to Regular Expressions, 
+          see these sites <a href="http://www.zend.com/zend/tut/tutorial-delin2.php" target="_blank">regular-expressions 
+          tutorial</a> or <a href="http://perso.wanadoo.fr/joseph.rezeau/eao/developpement/expandRegexpToString.htm#" 
+          target="_blank">rezeau.org</a>. </p>
+      <h3>Correct answer matching a regular expression pattern </h3>
+      <p>It is not possible to give complete examples of the vast possibilities offered 
+          by this system, and the following are just some possibilities. </p>
+      <p><strong>Example 1.</strong> Suppose your question is &quot;What are the colors 
+          of the French flag?&quot;. In the Answer 1 frame you type this regular 
+          expression: &quot;<span class="c_computeroutput">it&rsquo;s blue, white(,| and) 
+          red</span>/i&quot;. This will match any of those four student answers:</p>
+      <ul>
+        <li>it&rsquo;s blue, white, red</li>
+        <li>it&rsquo;s blue, white and red</li>
+        <li>It&rsquo;s blue, white, red</li>
+        <li>It&rsquo;s blue, white and red </li>
+      </ul>
+      <p>Please note that by default a regular expression match is case sensitive; to 
+          make the match case insensitive you must add the <strong>/i</strong> parameter 
+          right at the end of your expression.</p>
+      <p><strong>Example 2</strong>. Question: &quot;What is blue, or red, or yellow?&quot;. 
+          Answer: &quot;(|it's )a colou?r&quot;. This will match:</p>
+      <ul>
+        <li>a colour</li>
+        <li> a color</li>
+        <li>it's a colour</li>
+        <li>it's a color</li>
+      </ul>
+      <p>Notes.- The beginning of this regular expression &quot;(|it's )&quot; will 
+          match either nothing or &quot;it's  &quot; (i.e. &quot;it's&quot; followed by 
+          a space). The ? (question-mark) means: preceding character zero or one time; 
+          it is used here to match British English as well as US spelling.</p>
+      <p><strong>Example 3.</strong> Question: &quot;Name an animal whose name is made 
+          of 3 letters and the middle letter is the vowel <em>a</em>&quot;. Anwer: 
+          &quot;[bcr]at&quot;. This will match: bat, cat and rat. </p>
+      <h3>Detecting missing required words or character strings</h3>
+      <p>Regular expressions alone cannot detect absent character strings, so you have to 
+          add a little code in your Answer to take care of this. Any Teacher Answer which 
+          begins with a double hyphen will analyse the student&rsquo;s answer to find out 
+          whether the following string is present or absent. If present, the analysis 
+          continues to the next question; if absent, the analysis stops and the relevant 
+          Response message is displayed.</p>
+      <p><strong>Example 4.  </strong></p>
+      <ul>
+        <li>Answer 2: <span class="c_computeroutput">--.*blue.*</span>/i</li>
+        <li>student answer: &quot;it's red and white&quot; </li>
+        <li>Response 2: <span class="c_computeroutput">The color of the sky is missing!</span></li>
+        <li>Jump 2: <span class="c_computeroutput">this page</span></li>
+      </ul>
+      <p>Here, the . (dot) stands for &ldquo;any character&rdquo; and the * (asterisk) 
+          means &ldquo;preceding special character repeated any number of times&rdquo;. 
+          The Answer2 regular expression above means: check whether the character string 
+          &quot;blue&quot;, preceded with anything and followed by anything is absent 
+          from the student's answer. Please note that the use of the asterisk is different 
+          in the Simple analysis system and in the Regular Expressions system.</p>
+      <p><strong>Example 5.</strong> Question: &quot;Name an animal whose name is made of 
+          3 letters and the middle letter is the vowel <em>a</em>&quot;. Teacher Answer: &quot;--[b|c|r]&quot;. Response: &quot;Your answer should start with one of these letters: b, c or r&quot; </p>
+      <h3>Detecting unwanted (incorrect) words or character strings</h3>
+      <p>You may want to detect, in the student's answer, the presence of one or several 
+          words which should be <strong>not</strong> be there (because they are wrong) and 
+          to single them out with a specific response. Just start your teacher Answer by a 
+          double plus sign (++). </p>
+      <p><strong>Example 6. </strong></p>
+      <ul>
+        <li>Answer 3: ++(yellow|black|orange|green|black|pink)/i</li>
+        <li>student answer: &quot;it's blue, orange and white&quot; </li>
+        <li>Response 3: One or more colors are wrong!</li>
+        <li>Jump 3: this page</li></ul>
+        <p>If any of these (wrong) colors is detected in the student&rsquo;s answer, 
+            then the negative feedback message (Response 3) will be displayed and the 
+            wrong strings will be colored red (or the color of the .incorrect class if 
+            it exists in a CSS stylesheet of your active theme).</p>
+      <p><strong>Example 7</strong>. Question: &quot;Name an animal whose name is made 
+          of 3 letters and the middle letter is the vowel <em>a</em>&quot;. Teacher 
+          Answer: &quot;++hat&quot;. Response: &quot;You might wear one made of an 
+          animal's skin, but a hat can't be considered as an animal.&quot;   </p>
+      <h3>Escaping special characters </h3>
+      <p>If you need to use characters which are part of the regular expressions set 
+          of <em>special characters</em>, you need to &quot;escape&quot; them (i.e. precede 
+          them with a backslash). E.g. if you want to accept the answer &quot;My computer 
+          cost 1000$&quot;, you must write the regular expression as &quot;My computer cost 
+          1000\$&quot;. The special characters which must be escaped are .^$*()[]+?|</p>
+    </li>
+  </ul>
+</li>
+
+<li><p><b>True/False</b> The answer to this type of question only has two options,
+    true or false. The student is prompted to choose which is the correct
+    option. This type of question is basically a Multichoice question with just
+    two choices.</p></li>
+
+<li><p><b>Matching</b> These are quite powerful and flexible questions. They
+    consist of a list of names or statements which must be correctly matched
+    against other list of names or statements. For example &quot;Match the
+    Capital with the Country&quot; with the two lists Japan, Canada, Italy and
+    Tokyo, Ottawa, Rome. It is possible to have repeated entries in one of the
+    lists but care should be taken to make the repeats identical. For example
+    &quot;Identify the type of these creatures&quot; with the lists Sparrow,
+    Cow, Ant, Dog and Bird, Animal, Insect, Animal. </p>
+
+<p>When creating this type of question the items for the first list go into the
+    Answer boxes and items for the second list go into the Response boxes. Once
+    created a more sensible labeling scheme is shown. When the student
+    successfully matches the items the jump on the first answer is used. An
+    unsuccessful answer jumps to the page on the second answer. The question does
+    <b>not</b> support custom responses, the student is told how many matches
+    are correct or if all the matches are correct.</p>
+
+<p>Unlike the Multichoice question where the choices are shown in a random
+    order, the first list of items is <b>not</b> shuffled but shown in the same
+    order as entered. This allows for <b>&quot;Ordered&quot;</b> questions to be
+    constructed. Consider the question &quot; Put the following into the order
+    they were born, the earliest first&quot; with the lists 1., 2., 3., 4. and
+    Longfellow, Lawrence, Lowell, Larkin. The second list is shuffed before
+    being used in the question, of course.</p></li>
+
+<li><p><b>Numerical</b> This type of question requires a number as the answer.
+    In it's simplest form it requires just one answer to be specified. For
+    example &quot;What is 2 plus 2?&quot; with the answer 4 given a forward
+    jump. However, it is better to specify a range because the internal rounding
+    of numerical values can make single numeric comparisons rather hit or miss.
+    Thus, if the question were &quot;What is 10 divided by 3&quot; it would be
+    necessary to give the answer as <b>&quot;Minimum:Maximum&quot;</b>, that
+    is <b>two</b> values separated by a colon (:). Thus if 3.33:3.34 is given as the
+    acceptable range for the answer, then the answers 3.33, 3.333, 3.3333...
+    would all be taken as correct answers. &quot;Wrong&quot; answers would
+    include 3.3 (less than the minimum) and 3.4 (greater than the maximum).</p>
+
+<p>More than one correct answer is allowed and the answers can be either single
+    or pair of values. Note that the order in which the answers are tested is
+    Answer 1, Answer 2... so some care needs to taken if the desired response
+    is to appear. For example the question &quot;When was Larkin born?&quot;
+    could have the single value of 1922, the exact answer, and the pair of
+    values 1920:1929, the 20's, as the less exact answer.The order in which
+    these values should be tested is, obviously, 1922 then 1920:1929. The
+    first answer might have the response &quot;That's exactly right&quot;
+    while the other answer's response might be &quot;That's close, you've got
+    the right decade&quot;</p>
+
+<p>Wrong answers can be given but depending on their actual range, care should
+    be taken to place them after the correct answers. For example in adding the
+    wrong answer 3:4 to the &quot;10 divided by 3&quot; question it needs to come
+    after the correct answer. That is the answers are ordered 3.33:3.34 (the
+    &quot;correct&quot; answer) then 3:4 (the &quot;wrong&quot; answer, but
+    not wildly wrong answer!).</p></li>
+</ul>
+
index 035edc5..d5db116 100644 (file)
@@ -1,34 +1,34 @@
-<p align="center"><b>Upload groups</b></p>\r
-\r
-<p>This facility allows the batch upload of groups into Moodle.</p>\r
-\r
-\r
-<ul>\r
-  <li>Each line of the file contains one record</li>\r
-  <li>Each record is a series of data separated by commas</li>\r
-  <li>The first record of the file is special, and contains a list of fieldnames. This defines the format of the rest of the file.\r
-    <blockquote>\r
-      <p><strong>Required fieldnames:</strong> these fields must be included in the first record, and defined for each user</p>\r
-      <p></p>\r
-      <font color="#990000" face="Courier New, Courier, mono">groupname</font></p>\r
-</p>\r
-      <p><strong>Default fieldnames:</strong> these are optional - if they are not included then the values are taken from the current language and current course</p>\r
-      <p><font color="#990000" face="Courier New, Courier, mono">idnumber, coursename, lang</font> </p>\r
-      <p><strong>Optional fieldnames: </strong>all of these are completely optional. </p>\r
-      <p> <font color="#990000" face="Courier New, Courier, mono">description, picture, hidepicture</font></p>\r
-    </blockquote>\r
-    </li>\r
-  <li>Commas within the data should be encoded as &amp;#44 - the script will automatically decode these back to commas. </li>\r
-  <li>For Boolean fields, use 0 for false and 1 for true. </li>\r
-  <li>Either idnumber or coursename can be used to identify the course. Idnumber overrides coursename. If neither is specified, the groups will be added to the current course.\r
-  <li>Coursename is the course shortname.</li>\r
-  <li>Note: If a group is already registered in the Moodle database for a particular course, this script will return the \r
-      group name for that group. Teachers are only allowed to upload groups in courses they are authorized to edit.</li>\r
-</ul>\r
-   \r
-<p>Here is an example of a valid import file:</p>\r
-<p><font size="-1" face="Courier New, Courier, mono"></font>groupname,idnumber,lang,description,picture <br />\r
-group1, Phil101, en, this group requires extra attention!, 0 <br />\r
-group2, Math243, , ,\r
-</font></p>\r
-\r
+<p align="center"><b>Upload groups</b></p>
+
+<p>This facility allows the batch upload of groups into Moodle.</p>
+
+
+<ul>
+  <li>Each line of the file contains one record</li>
+  <li>Each record is a series of data separated by commas</li>
+  <li>The first record of the file is special, and contains a list of fieldnames. This defines the format of the rest of the file.
+    <blockquote>
+      <p><strong>Required fieldnames:</strong> these fields must be included in the first record, and defined for each user</p>
+      <p></p>
+      <font color="#990000" face="Courier New, Courier, mono">groupname</font></p>
+</p>
+      <p><strong>Default fieldnames:</strong> these are optional - if they are not included then the values are taken from the current language and current course</p>
+      <p><font color="#990000" face="Courier New, Courier, mono">idnumber, coursename, lang</font> </p>
+      <p><strong>Optional fieldnames: </strong>all of these are completely optional. </p>
+      <p> <font color="#990000" face="Courier New, Courier, mono">description, picture, hidepicture</font></p>
+    </blockquote>
+    </li>
+  <li>Commas within the data should be encoded as &amp;#44 - the script will automatically decode these back to commas. </li>
+  <li>For Boolean fields, use 0 for false and 1 for true. </li>
+  <li>Either idnumber or coursename can be used to identify the course. Idnumber overrides coursename. If neither is specified, the groups will be added to the current course.
+  <li>Coursename is the course shortname.</li>
+  <li>Note: If a group is already registered in the Moodle database for a particular course, this script will return the 
+      group name for that group. Teachers are only allowed to upload groups in courses they are authorized to edit.</li>
+</ul>
+   
+<p>Here is an example of a valid import file:</p>
+<p><font size="-1" face="Courier New, Courier, mono"></font>groupname,idnumber,lang,description,picture <br />
+group1, Phil101, en, this group requires extra attention!, 0 <br />
+group2, Math243, , ,
+</font></p>
+
index 4d37b58..f56c159 100644 (file)
@@ -1,28 +1,28 @@
-<?php \r
-\r
-$string['createSequence'] = 'Create new sequence';\r
-$string['editSequence'] = 'Edit selected sequence';\r
-$string['error'] = 'Sorry, an unknown error has occured.';\r
-$string['introduction']  = 'Introduction';\r
-$string['lams'] = '-- LAMS - Learning Activity Management System --';\r
-$string['lamsoutline'] = 'LAMS Outline';\r
-$string['lesson']="learning session";\r
-$string['modulename'] = 'LAMS';\r
-$string['modulenameplural'] = 'LAMS';\r
-$string['notsetup'] = 'NOT_SET_UP';\r
-$string['openauthor'] = 'Open LAMS Author';\r
-$string['openlearner'] = 'Open LAMS Learner';\r
-$string['openmonitor'] = 'Open LAMS Monitor';\r
-$string['refreshSequenceList']  = 'Refresh sequence list';\r
-$string['selectExistingSequence'] = 'Select an existing sequence or create a new sequence.';\r
-$string['sequence'] = 'Select Sequence';\r
-$string['serverid'] = 'Enter the server ID received from <a href=http://www.lamsinternational.com target=_blank>LAMS international</a>.';\r
-$string['serverkey'] = 'Enter the server key received from <a href=http://www.lamsinternational.com target=_blank>LAMS international</a>.';\r
-$string['serverurl'] = 'Enter the basic URL used to access the LAMS server. For example http://localhost:8080/lams';\r
-$string['useSequence']  = 'Use selected sequence';\r
-$string['visibletostudents'] = 'Show activity to students';\r
-$string['wikistartederror'] = 'Wiki already has entries - can\'t change.';\r
-$string['workspace'] = 'Select Workspace';\r
-$string['wrongversionrange'] = '$a is not a correct range!';\r
-\r
-?>\r
+<?php 
+
+$string['createSequence'] = 'Create new sequence';
+$string['editSequence'] = 'Edit selected sequence';
+$string['error'] = 'Sorry, an unknown error has occured.';
+$string['introduction']  = 'Introduction';
+$string['lams'] = '-- LAMS - Learning Activity Management System --';
+$string['lamsoutline'] = 'LAMS Outline';
+$string['lesson']="learning session";
+$string['modulename'] = 'LAMS';
+$string['modulenameplural'] = 'LAMS';
+$string['notsetup'] = 'NOT_SET_UP';
+$string['openauthor'] = 'Open LAMS Author';
+$string['openlearner'] = 'Open LAMS Learner';
+$string['openmonitor'] = 'Open LAMS Monitor';
+$string['refreshSequenceList']  = 'Refresh sequence list';
+$string['selectExistingSequence'] = 'Select an existing sequence or create a new sequence.';
+$string['sequence'] = 'Select Sequence';
+$string['serverid'] = 'Enter the server ID received from <a href=http://www.lamsinternational.com target=_blank>LAMS international</a>.';
+$string['serverkey'] = 'Enter the server key received from <a href=http://www.lamsinternational.com target=_blank>LAMS international</a>.';
+$string['serverurl'] = 'Enter the basic URL used to access the LAMS server. For example http://localhost:8080/lams';
+$string['useSequence']  = 'Use selected sequence';
+$string['visibletostudents'] = 'Show activity to students';
+$string['wikistartederror'] = 'Wiki already has entries - can\'t change.';
+$string['workspace'] = 'Select Workspace';
+$string['wrongversionrange'] = '$a is not a correct range!';
+
+?>
index c9a924c..ff585a6 100644 (file)
@@ -1,65 +1,65 @@
-\r
-<?php \r
-    // only display this help message if we are being forced to change\r
-    if ($forcepassword) {\r
-        notify( get_string('forcepasswordchangenotice') );\r
-    }\r
- ?>\r
-<p><b><?php print_string("allfieldsrequired") ?></b></p>\r
-<?php\r
-   if (empty($frm->username)) {\r
-       $frm->username = "";\r
-   }\r
-   if (empty($frm->password)) {\r
-       $frm->password = "";\r
-   }\r
-   if (empty($frm->newpassword1)) {\r
-       $frm->newpassword1 = "";\r
-   }\r
-   if (empty($frm->newpassword2)) {\r
-       $frm->newpassword2 = "";\r
-   }\r
-?>\r
-<form action="change_password.php" method="post" name="form" id="form">\r
-<table cellpadding="10">\r
-\r
-<tr valign="top">\r
-    <td><?php print_string("username") ?>:</td>\r
-    <td>\r
-    <?php if (has_capability('moodle/user:update',get_context_instance(CONTEXT_SYSTEM, SITEID)) || empty($frm->username)) { ?>\r
-        <input type="text" name="username" size="25" value="<?php p($frm->username) ?>" alt="<?php print_string("username") ?>" />\r
-    <?php } else { ?>\r
-        <input type="hidden" name="username" value="<?php p($frm->username)?>" />  <?php p($frm->username)?>\r
-    <?php } ?>\r
-    <?php if (!empty($err->username)) { formerr($err->username); } ?>\r
-    </td>\r
-</tr>\r
-\r
-<?php if (!ihas_capability('moodle/user:update',get_context_instance(CONTEXT_SYSTEM, SITEID))) { ?>\r
-    <tr valign="top">\r
-        <td><?php print_string("oldpassword") ?>:</td>\r
-        <td><input type="password" name="password" size="25" value="<?php p($frm->password) ?>" alt="<?php print_string("password") ?>" />\r
-        <?php if (!empty($err->password)) { formerr($err->password); } ?>\r
-        </td>\r
-    </tr>\r
-<?php } ?>\r
-\r
-<tr valign="top">\r
-    <td><?php print_string("newpassword") ?>:</td>\r
-    <td><input type="password" name="newpassword1" size="25" value="<?php p($frm->newpassword1) ?>" alt="<?php print_string("newpassword") ?>" />\r
-    <?php if (!empty($err->newpassword1)) { formerr($err->newpassword1); } ?>\r
-    </td>\r
-</tr>\r
-<tr valign="top">\r
-    <td><?php print_string("newpassword") ?> (<?php print_string("again") ?>):</td>\r
-    <td><input type="password" name="newpassword2" size="25" value="<?php p($frm->newpassword2) ?>" alt="<?php print_string("newpassword") ?> (<?php print_string("again") ?>)" />\r
-    <?php if (!empty($err->newpassword2)) { formerr($err->newpassword2); } ?>\r
-    </td>\r
-</tr>\r
-<tr>\r
-    <td></td>\r
-    <td><input type="hidden" name="id" value="<?php p($frm->id)?>" />\r
-    <input type="submit" value="<?php print_string("changepassword") ?>" /></td>\r
-    </tr>\r
-  </table>\r
-</form>\r
+
+<?php 
+    // only display this help message if we are being forced to change
+    if ($forcepassword) {
+        notify( get_string('forcepasswordchangenotice') );
+    }
+ ?>
+<p><b><?php print_string("allfieldsrequired") ?></b></p>
+<?php
+   if (empty($frm->username)) {
+       $frm->username = "";
+   }
+   if (empty($frm->password)) {
+       $frm->password = "";
+   }
+   if (empty($frm->newpassword1)) {
+       $frm->newpassword1 = "";
+   }
+   if (empty($frm->newpassword2)) {
+       $frm->newpassword2 = "";
+   }
+?>
+<form action="change_password.php" method="post" name="form" id="form">
+<table cellpadding="10">
+
+<tr valign="top">
+    <td><?php print_string("username") ?>:</td>
+    <td>
+    <?php if (has_capability('moodle/user:update',get_context_instance(CONTEXT_SYSTEM, SITEID)) || empty($frm->username)) { ?>
+        <input type="text" name="username" size="25" value="<?php p($frm->username) ?>" alt="<?php print_string("username") ?>" />
+    <?php } else { ?>
+        <input type="hidden" name="username" value="<?php p($frm->username)?>" />  <?php p($frm->username)?>
+    <?php } ?>
+    <?php if (!empty($err->username)) { formerr($err->username); } ?>
+    </td>
+</tr>
+
+<?php if (!ihas_capability('moodle/user:update',get_context_instance(CONTEXT_SYSTEM, SITEID))) { ?>
+    <tr valign="top">
+        <td><?php print_string("oldpassword") ?>:</td>
+        <td><input type="password" name="password" size="25" value="<?php p($frm->password) ?>" alt="<?php print_string("password") ?>" />
+        <?php if (!empty($err->password)) { formerr($err->password); } ?>
+        </td>
+    </tr>
+<?php } ?>
+
+<tr valign="top">
+    <td><?php print_string("newpassword") ?>:</td>
+    <td><input type="password" name="newpassword1" size="25" value="<?php p($frm->newpassword1) ?>" alt="<?php print_string("newpassword") ?>" />
+    <?php if (!empty($err->newpassword1)) { formerr($err->newpassword1); } ?>
+    </td>
+</tr>
+<tr valign="top">
+    <td><?php print_string("newpassword") ?> (<?php print_string("again") ?>):</td>
+    <td><input type="password" name="newpassword2" size="25" value="<?php p($frm->newpassword2) ?>" alt="<?php print_string("newpassword") ?> (<?php print_string("again") ?>)" />
+    <?php if (!empty($err->newpassword2)) { formerr($err->newpassword2); } ?>
+    </td>
+</tr>
+<tr>
+    <td></td>
+    <td><input type="hidden" name="id" value="<?php p($frm->id)?>" />
+    <input type="submit" value="<?php print_string("changepassword") ?>" /></td>
+    </tr>
+  </table>
+</form>
index e8e1258..ab27e9d 100644 (file)
@@ -1,82 +1,82 @@
-<?php\r
-    if (empty($form->resubmit)) {\r
-        $form->resubmit = 0;  //upload&rev: =1\r
-    }\r
-    if (empty($form->maxbytes)) {\r
-        $form->maxbytes = $CFG->assignment_maxbytes;\r
-    }\r
-    if (empty($form->emailteachers)) {\r
-        $form->emailteachers = '';\r
-    }\r
-    //allow multiple files (from new upload type)\r
-    if (empty($form->var1)) {\r
-        $form->var1 = 0; \r
-    }\r
-    //email to students (from upload&review)\r
-    if (empty($form->var2)) {\r
-        $form->var2 = '';\r
-    }\r
-\r
-?>\r
-\r
-<table align="center" cellpadding="5" cellspacing="0">\r
-\r
-<tr valign="top">\r
-    <td align="right"><b><?php print_string("maximumsize", "assignment") ?>:</b></td>\r
-    <td>\r
-    <?php\r
-        $choices = get_max_upload_sizes($CFG->maxbytes, $this->course->maxbytes);\r
-        choose_from_menu ($choices, "maxbytes", $form->maxbytes, "");\r
-    ?>\r
-  </td>\r
-</tr>\r
-<tr>\r
-    <td align="right"><b><?php print_string("allowmultiple", "assignment") ?>:</b></td>\r
-    <td>\r
-    <?php\r
-        $options[0] = get_string("no"); $options[1] = get_string("yes");\r
-        choose_from_menu($options, "var1", $form->var1, "");\r
-    ?>\r
-    </td>\r
-</tr>\r
-\r
-<tr>\r
-    <td align="right"><b><?php print_string("allowresubmit", "assignment") ?>:</b></td>\r
-    <td>\r
-    <?php \r
-        $options[0] = get_string("no"); $options[1] = get_string("yes");\r
-        choose_from_menu($options, "resubmit", $form->resubmit, ""); //that's how it's un U&R\r
-    //    choose_from_menu($options, "var2", $form->var2, "");\r
-        helpbutton("resubmit", get_string("allowresubmit", "assignment"), "assignment");\r
-    ?>\r
-    </td>\r
-</tr>\r
-\r
-<tr>\r
-    <td align="right"><b><?php print_string("emailteachers", "assignment") ?>:</b></td>\r
-    <td>\r
-    <?php \r
-        $options[0] = get_string("no"); $options[1] = get_string("yes");\r
-        choose_from_menu($options, "emailteachers", $form->emailteachers, "");\r
-        helpbutton("emailteachers", get_string("emailteachers", "assignment"), "assignment");\r
-    ?>\r
-    </td>\r
-</tr>\r
-<tr>\r
-        <td align="right"><b><?php print_string("emailstudents", "assignment") ?>:</b></td>\r
-        <td>\r
-        <?php\r
-                $options[0] = get_string("no"); $options[1] = get_string("yes");\r
-                choose_from_menu($options, "var2", $form->var2, "");\r
-        //        choose_from_menu($options, "emailstudents", $form->emailstudents, "");\r
-                helpbutton("emailstudents", get_string("emailstudents", "assignment"), "assignment");\r
-        ?>\r
-        </td>\r
-</tr>\r
-\r
-</table>\r
-\r
-<center>\r
-<br />\r
-<input type="submit" value="<?php print_string("continue") ?>" />\r
-</center>\r
+<?php
+    if (empty($form->resubmit)) {
+        $form->resubmit = 0;  //upload&rev: =1
+    }
+    if (empty($form->maxbytes)) {
+        $form->maxbytes = $CFG->assignment_maxbytes;
+    }
+    if (empty($form->emailteachers)) {
+        $form->emailteachers = '';
+    }
+    //allow multiple files (from new upload type)
+    if (empty($form->var1)) {
+        $form->var1 = 0; 
+    }
+    //email to students (from upload&review)
+    if (empty($form->var2)) {
+        $form->var2 = '';
+    }
+
+?>
+
+<table align="center" cellpadding="5" cellspacing="0">
+
+<tr valign="top">
+    <td align="right"><b><?php print_string("maximumsize", "assignment") ?>:</b></td>
+    <td>
+    <?php
+        $choices = get_max_upload_sizes($CFG->maxbytes, $this->course->maxbytes);
+        choose_from_menu ($choices, "maxbytes", $form->maxbytes, "");
+    ?>
+  </td>
+</tr>
+<tr>
+    <td align="right"><b><?php print_string("allowmultiple", "assignment") ?>:</b></td>
+    <td>
+    <?php
+        $options[0] = get_string("no"); $options[1] = get_string("yes");
+        choose_from_menu($options, "var1", $form->var1, "");
+    ?>
+    </td>
+</tr>
+
+<tr>
+    <td align="right"><b><?php print_string("allowresubmit", "assignment") ?>:</b></td>
+    <td>
+    <?php 
+        $options[0] = get_string("no"); $options[1] = get_string("yes");
+        choose_from_menu($options, "resubmit", $form->resubmit, ""); //that's how it's un U&R
+    //    choose_from_menu($options, "var2", $form->var2, "");
+        helpbutton("resubmit", get_string("allowresubmit", "assignment"), "assignment");
+    ?>
+    </td>
+</tr>
+
+<tr>
+    <td align="right"><b><?php print_string("emailteachers", "assignment") ?>:</b></td>
+    <td>
+    <?php 
+        $options[0] = get_string("no"); $options[1] = get_string("yes");
+        choose_from_menu($options, "emailteachers", $form->emailteachers, "");
+        helpbutton("emailteachers", get_string("emailteachers", "assignment"), "assignment");
+    ?>
+    </td>
+</tr>
+<tr>
+        <td align="right"><b><?php print_string("emailstudents", "assignment") ?>:</b></td>
+        <td>
+        <?php
+                $options[0] = get_string("no"); $options[1] = get_string("yes");
+                choose_from_menu($options, "var2", $form->var2, "");
+        //        choose_from_menu($options, "emailstudents", $form->emailstudents, "");
+                helpbutton("emailstudents", get_string("emailstudents", "assignment"), "assignment");
+        ?>
+        </td>
+</tr>
+
+</table>
+
+<center>
+<br />
+<input type="submit" value="<?php print_string("continue") ?>" />
+</center>
index 2e4d3bf..4710792 100755 (executable)
-rem\r
-rem Table structure for table chat\r
-rem\r
-\r
-drop TABLE prefix_chat;\r
-CREATE TABLE prefix_chat (\r
-  id number(10) primary key,\r
-  course number(10) default '0' not null,\r
-  name varchar2(255) default '' not null,\r
-  intro varchar2(1024) NOT NULL,\r
-  keepdays number(11) default '0' not null,\r
-  studentlogs number(4) default '0' not null,\r
-  chattime number(10) default '0' not null,\r
-  schedule number(4) default '0' not null,\r
-  timemodified number(10) default '0' not null\r
-);\r
-\r
-\r
-COMMENT on table prefix_chat is 'Each of these is a chat room';\r
-\r
-drop sequence p_chat_seq;\r
-create sequence p_chat_seq;\r
-\r
-create or replace trigger p_chat_trig\r
-  before insert on prefix_chat\r
-  referencing new as new_row\r
-  for each row\r
-  begin\r
-    select p_chat_seq.nextval into :new_row.id from dual;\r
-  end;\r
-.\r
-/\r
-\r
-insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(1,'name 1','intro 1',1,1,1,1,1);\r
-insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(2,'name 2','intro 2',2,2,2,2,2);\r
-insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(3,'name 3','intro 3',3,3,3,3,3);\r
-insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(4,'name 4','intro 4',4,4,4,4,4);\r
-\r
-select * from prefix_chat;\r
-\r
-rem --------------------------------------------------------\r
-rem\r
-rem Table structure for table chat_messages\r
-rem\r
-\r
-drop TABLE prefix_chat_messages;\r
-CREATE TABLE prefix_chat_messages (\r
-  id number(10) primary key,\r
-  chatid number(10) default '0' not null,\r
-  userid number(10) default '0' not null,\r
-  system number(1) default '0' not null,\r
-  message varchar2(1024) NOT NULL,\r
-  timestamp number(10) default '0' not null\r
-);\r
-\r
-COMMENT on table prefix_chat_messages is 'Stores all the actual chat messages';\r
-\r
-create index timemodifiedchat on prefix_chat_messages(timestamp,chatid);\r
-\r
-drop sequence p_chat_messages_seq;\r
-create sequence p_chat_messages_seq;\r
-\r
-create or replace trigger p_chat_messages_trig\r
-  before insert on prefix_chat_messages\r
-  referencing new as new_row\r
-  for each row\r
-  begin\r
-    select p_chat_messages_seq.nextval into :new_row.id from dual;\r
-  end;\r
-.\r
-/\r
-\r
-insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(1,1,1,'message1',1);\r
-insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(2,2,2,'message2',2);\r
-insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(3,3,3,'message3',3);\r
-insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(4,4,4,'message4',4);\r
-\r
-select * from prefix_chat_messages;\r
-\r
-rem --------------------------------------------------------\r
-\r
-rem\r
-rem Table structure for table chat_users\r
-rem\r
-\r
-drop TABLE prefix_chat_users;\r
-CREATE TABLE prefix_chat_users (\r
-  id number(10) primary key,\r
-  chatid number(11) default '0' not null,\r
-  userid number(11) default '0' not null,\r
-  version varchar2(16) default '' not null,\r
-  ip varchar2(15) default '' not null,\r
-  firstping number(10) default '0' not null,\r
-  lastping number(10) default '0' not null,\r
-  lastmessageping number(10) default '0' not null,\r
-  sid varchar2(32) default '' not null,\r
-  course number(10) default '0' not null,\r
-  lang varchar2(10) default '' not null\r
-);\r
-\r
-create index userid on prefix_chat_users(userid);\r
-create index lastping on prefix_chat_users(lastping);\r
-\r
-drop sequence p_chat_users_seq;\r
-create sequence p_chat_users_seq;\r
-\r
-create or replace trigger p_chat_users_trig\r
-  before insert on prefix_chat_users\r
-  referencing new as new_row\r
-  for each row\r
-  begin\r
-    select p_chat_users_seq.nextval into :new_row.id from dual;\r
-  end;\r
-.\r
-/\r
-\r
-COMMENT on table prefix_chat_users is 'Keeps track of which users are in which chat rooms';\r
-\r
-insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(1,1,'version1','ip1',1,1,1,'sid1');\r
-insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(2,2,'version2','ip2',2,2,2,'sid2');\r
-insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(3,3,'version3','ip3',3,3,3,'sid3');\r
-insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(4,4,'version4','ip4',4,4,4,'sid4');\r
-\r
-select * from prefix_chat_users;\r
-\r
-delete from prefix_log_display where module='chat';\r
-\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'view', 'chat', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'add', 'chat', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'update', 'chat', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'report', 'chat', 'name');\r
-\r
-select * from prefix_log_display where module='chat' order by 1,2,3,4;\r
+rem
+rem Table structure for table chat
+rem
+
+drop TABLE prefix_chat;
+CREATE TABLE prefix_chat (
+  id number(10) primary key,
+  course number(10) default '0' not null,
+  name varchar2(255) default '' not null,
+  intro varchar2(1024) NOT NULL,
+  keepdays number(11) default '0' not null,
+  studentlogs number(4) default '0' not null,
+  chattime number(10) default '0' not null,
+  schedule number(4) default '0' not null,
+  timemodified number(10) default '0' not null
+);
+
+
+COMMENT on table prefix_chat is 'Each of these is a chat room';
+
+drop sequence p_chat_seq;
+create sequence p_chat_seq;
+
+create or replace trigger p_chat_trig
+  before insert on prefix_chat
+  referencing new as new_row
+  for each row
+  begin
+    select p_chat_seq.nextval into :new_row.id from dual;
+  end;
+.
+/
+
+insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(1,'name 1','intro 1',1,1,1,1,1);
+insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(2,'name 2','intro 2',2,2,2,2,2);
+insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(3,'name 3','intro 3',3,3,3,3,3);
+insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(4,'name 4','intro 4',4,4,4,4,4);
+
+select * from prefix_chat;
+
+rem --------------------------------------------------------
+rem
+rem Table structure for table chat_messages
+rem
+
+drop TABLE prefix_chat_messages;
+CREATE TABLE prefix_chat_messages (
+  id number(10) primary key,
+  chatid number(10) default '0' not null,
+  userid number(10) default '0' not null,
+  system number(1) default '0' not null,
+  message varchar2(1024) NOT NULL,
+  timestamp number(10) default '0' not null
+);
+
+COMMENT on table prefix_chat_messages is 'Stores all the actual chat messages';
+
+create index timemodifiedchat on prefix_chat_messages(timestamp,chatid);
+
+drop sequence p_chat_messages_seq;
+create sequence p_chat_messages_seq;
+
+create or replace trigger p_chat_messages_trig
+  before insert on prefix_chat_messages
+  referencing new as new_row
+  for each row
+  begin
+    select p_chat_messages_seq.nextval into :new_row.id from dual;
+  end;
+.
+/
+
+insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(1,1,1,'message1',1);
+insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(2,2,2,'message2',2);
+insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(3,3,3,'message3',3);
+insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(4,4,4,'message4',4);
+
+select * from prefix_chat_messages;
+
+rem --------------------------------------------------------
+
+rem
+rem Table structure for table chat_users
+rem
+
+drop TABLE prefix_chat_users;
+CREATE TABLE prefix_chat_users (
+  id number(10) primary key,
+  chatid number(11) default '0' not null,
+  userid number(11) default '0' not null,
+  version varchar2(16) default '' not null,
+  ip varchar2(15) default '' not null,
+  firstping number(10) default '0' not null,
+  lastping number(10) default '0' not null,
+  lastmessageping number(10) default '0' not null,
+  sid varchar2(32) default '' not null,
+  course number(10) default '0' not null,
+  lang varchar2(10) default '' not null
+);
+
+create index userid on prefix_chat_users(userid);
+create index lastping on prefix_chat_users(lastping);
+
+drop sequence p_chat_users_seq;
+create sequence p_chat_users_seq;
+
+create or replace trigger p_chat_users_trig
+  before insert on prefix_chat_users
+  referencing new as new_row
+  for each row
+  begin
+    select p_chat_users_seq.nextval into :new_row.id from dual;
+  end;
+.
+/
+
+COMMENT on table prefix_chat_users is 'Keeps track of which users are in which chat rooms';
+
+insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(1,1,'version1','ip1',1,1,1,'sid1');
+insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(2,2,'version2','ip2',2,2,2,'sid2');
+insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(3,3,'version3','ip3',3,3,3,'sid3');
+insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(4,4,'version4','ip4',4,4,4,'sid4');
+
+select * from prefix_chat_users;
+
+delete from prefix_log_display where module='chat';
+
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'view', 'chat', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'add', 'chat', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'update', 'chat', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'report', 'chat', 'name');
+
+select * from prefix_log_display where module='chat' order by 1,2,3,4;
index 6cef94d..d89c9e5 100644 (file)
@@ -1,72 +1,72 @@
-<?php  // $Id$\r
-\r
-    $nomoodlecookie = true;     // Session not needed!\r
-\r
-    require('../../../config.php');\r
-    require('../lib.php');\r
-\r
-    $chat_sid = required_param('chat_sid', PARAM_ALPHANUM);\r
-\r
-    if (!$chatuser = get_record('chat_users', 'sid', $chat_sid)) {\r
-        error('Not logged in!');\r
-    }\r
-\r
-    chat_force_language($chatuser->lang);\r
-\r
-    ob_start();\r
-    ?>\r
-<script type="text/javascript">\r
-<!--\r
-\r
-scroll_active = true;\r
-function empty_field_and_submit() {\r
-    var cf   = document.getElementById('sendform');\r
-    var inpf = document.getElementById('inputform');\r
-    cf.chat_msgidnr.value = parseInt(cf.chat_msgidnr.value) + 1;\r
-    cf.chat_message.value = inpf.chat_message.value;\r
-    inpf.chat_message.value='';\r
-    cf.submit();\r
-    inpf.chat_message.focus();\r
-    return false;\r
-}\r
-function prepareusers() {\r
-    var frm = window.parent.frames;\r
-    for(i = 0; i < frm.length; ++i) {\r
-        if(frm[i].name == "users") {\r
-            window.userFrame = frm[i];\r
-            window.userHREF  = frm[i].location.href;\r
-            window.setTimeout("reloadusers();", <?php echo $CFG->chat_refresh_userlist; ?> * 1000);\r
-        }\r
-    }\r
-}\r
-function reloadusers() {\r
-    if(window.userFrame) {\r
-        window.userFrame.location.href = window.userFrame.location.href;\r
-        window.setTimeout("reloadusers();", <?php echo $CFG->chat_refresh_userlist; ?> * 1000);\r
-    }\r
-}\r
-// -->\r
-</script>\r
-    <?php\r
-\r
-    $meta = ob_get_clean();\r
-    // TODO: there will be two onload in body tag, does it matter?\r
-    print_header('', '', '', 'inputform.chat_message', $meta, false, '&nbsp;', '', false, 'onload="setfocus(); prepareusers();"');\r
-\r
-?>\r
-\r
-    <form action="../empty.php" method="get" target="empty" id="inputform"\r
-          onsubmit="return empty_field_and_submit();">\r
-        &gt;&gt;<input type="text" name="chat_message" size="60" value="" />\r
-        <?php helpbutton("chatting", get_string("helpchatting", "chat"), "chat", true, false); ?>\r
-    </form>\r
-    \r
-    <form action="<?php echo "http://$CFG->chat_serverhost:$CFG->chat_serverport/"; ?>" method="get" target="empty" id="sendform">\r
-        <input type="hidden" name="win" value="message" />\r
-        <input type="hidden" name="chat_message" value="" />\r
-        <input type="hidden" name="chat_msgidnr" value="0" />\r
-        <input type="hidden" name="chat_sid" value="<?php echo $chat_sid ?>" />\r
-    </form>\r
-</body>\r
-\r
-</html>\r
+<?php  // $Id$
+
+    $nomoodlecookie = true;     // Session not needed!
+
+    require('../../../config.php');
+    require('../lib.php');
+
+    $chat_sid = required_param('chat_sid', PARAM_ALPHANUM);
+
+    if (!$chatuser = get_record('chat_users', 'sid', $chat_sid)) {
+        error('Not logged in!');
+    }
+
+    chat_force_language($chatuser->lang);
+
+    ob_start();
+    ?>
+<script type="text/javascript">
+<!--
+
+scroll_active = true;
+function empty_field_and_submit() {
+    var cf   = document.getElementById('sendform');
+    var inpf = document.getElementById('inputform');
+    cf.chat_msgidnr.value = parseInt(cf.chat_msgidnr.value) + 1;
+    cf.chat_message.value = inpf.chat_message.value;
+    inpf.chat_message.value='';
+    cf.submit();
+    inpf.chat_message.focus();
+    return false;
+}
+function prepareusers() {
+    var frm = window.parent.frames;
+    for(i = 0; i < frm.length; ++i) {
+        if(frm[i].name == "users") {
+            window.userFrame = frm[i];
+            window.userHREF  = frm[i].location.href;
+            window.setTimeout("reloadusers();", <?php echo $CFG->chat_refresh_userlist; ?> * 1000);
+        }
+    }
+}
+function reloadusers() {
+    if(window.userFrame) {
+        window.userFrame.location.href = window.userFrame.location.href;
+        window.setTimeout("reloadusers();", <?php echo $CFG->chat_refresh_userlist; ?> * 1000);
+    }
+}
+// -->
+</script>
+    <?php
+
+    $meta = ob_get_clean();
+    // TODO: there will be two onload in body tag, does it matter?
+    print_header('', '', '', 'inputform.chat_message', $meta, false, '&nbsp;', '', false, 'onload="setfocus(); prepareusers();"');
+
+?>
+
+    <form action="../empty.php" method="get" target="empty" id="inputform"
+          onsubmit="return empty_field_and_submit();">
+        &gt;&gt;<input type="text" name="chat_message" size="60" value="" />
+        <?php helpbutton("chatting", get_string("helpchatting", "chat"), "chat", true, false); ?>
+    </form>
+    
+    <form action="<?php echo "http://$CFG->chat_serverhost:$CFG->chat_serverport/"; ?>" method="get" target="empty" id="sendform">
+        <input type="hidden" name="win" value="message" />
+        <input type="hidden" name="chat_message" value="" />
+        <input type="hidden" name="chat_msgidnr" value="0" />
+        <input type="hidden" name="chat_sid" value="<?php echo $chat_sid ?>" />
+    </form>
+</body>
+
+</html>
index 658cb6b..ca6c905 100755 (executable)
@@ -1,93 +1,93 @@
-rem\r
-rem Table structure for table choice\r
-rem\r
-\r
-drop TABLE prefix_choice;\r
-CREATE TABLE prefix_choice (\r
-  id number(10) primary key,\r
-  course number(10) default '0' not null,\r
-  name varchar2(255) default '' not null,\r
-  text varchar2(1024) NOT NULL,\r
-  format number(2) default '0' not null,\r
-  answer1 varchar2(255) default 'Yes' not null,\r
-  answer2 varchar2(255) default 'No' not null,\r
-  answer3 varchar2(255) default NULL,\r
-  answer4 varchar2(255) default NULL,\r
-  answer5 varchar2(255) default NULL,\r
-  answer6 varchar2(255) default NULL,\r
-  publish number(2) default '0' not null,\r
-  timemodified number(10) default '0' not null\r
-);\r
-\r
-COMMENT on table prefix_choice is 'Available choices are stored here.';\r
-\r
-drop sequence p_choice_seq;\r
-create sequence p_choice_seq;\r
-\r
-create or replace trigger p_choice_trig\r
-  before insert on prefix_choice\r
-  referencing new as new_row\r
-  for each row\r
-  begin\r
-    select p_choice_seq.nextval into :new_row.id from dual;\r
-  end;\r
-.\r
-/\r
-\r
-insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(1,'name1','text1',1,'1','1','1','1','1','1',1,1);\r
-insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(2,'name2','text2',2,'2','2','2','2','2','2',2,2);\r
-insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(3,'name3','text3',3,'3','3','3','3','3','3',3,3);\r
-insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(4,'name4','text4',4,'4','4','4','4','4','4',4,4);\r
-\r
-select * from prefix_choice order by 1,2;\r
-\r
-rem --------------------------------------------------------\r
-\r
-rem\r
-rem Table structure for table choice_answers\r
-rem\r
-\r
-drop TABLE prefix_choice_answers;\r
-CREATE TABLE prefix_choice_answers (\r
-  id number(10) primary key,\r
-  choice number(10) default '0' not null,\r
-  userid number(10) default '0' not null,\r
-  answer number(4) default '0' not null,\r
-  timemodified number(10) default '0' not null\r
-);\r
-\r
-comment on table prefix_choice_answers is 'Answers for each choice';\r
-\r
-drop sequence p_choice_answers_seq;\r
-create sequence p_choice_answers_seq;\r
-\r
-create or replace trigger p_choice_answers_trig\r
-  before insert on prefix_choice_answers\r
-  referencing new as new_row\r
-  for each row\r
-  begin\r
-    select p_choice_answers_seq.nextval into :new_row.id from dual;\r
-  end;\r
-.\r
-/\r
-\r
-insert into prefix_choice_answers (choice,userid,answer,timemodified) values(1,1,1,1);\r
-insert into prefix_choice_answers (choice,userid,answer,timemodified) values(2,2,2,2);\r
-insert into prefix_choice_answers (choice,userid,answer,timemodified) values(3,3,3,3);\r
-insert into prefix_choice_answers (choice,userid,answer,timemodified) values(4,4,4,4);\r
-\r
-select * from prefix_choice_answers order by 1,2;\r
-\r
-rem\r
-rem Dumping data for table log_display\r
-rem\r
-\r
-delete from prefix_log_display where module = 'choice';\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'view', 'choice', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'update', 'choice', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'add', 'choice', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'report', 'choice', 'name');\r
-\r
-    \r
-\r
-\r
+rem
+rem Table structure for table choice
+rem
+
+drop TABLE prefix_choice;
+CREATE TABLE prefix_choice (
+  id number(10) primary key,
+  course number(10) default '0' not null,
+  name varchar2(255) default '' not null,
+  text varchar2(1024) NOT NULL,
+  format number(2) default '0' not null,
+  answer1 varchar2(255) default 'Yes' not null,
+  answer2 varchar2(255) default 'No' not null,
+  answer3 varchar2(255) default NULL,
+  answer4 varchar2(255) default NULL,
+  answer5 varchar2(255) default NULL,
+  answer6 varchar2(255) default NULL,
+  publish number(2) default '0' not null,
+  timemodified number(10) default '0' not null
+);
+
+COMMENT on table prefix_choice is 'Available choices are stored here.';
+
+drop sequence p_choice_seq;
+create sequence p_choice_seq;
+
+create or replace trigger p_choice_trig
+  before insert on prefix_choice
+  referencing new as new_row
+  for each row
+  begin
+    select p_choice_seq.nextval into :new_row.id from dual;
+  end;
+.
+/
+
+insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(1,'name1','text1',1,'1','1','1','1','1','1',1,1);
+insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(2,'name2','text2',2,'2','2','2','2','2','2',2,2);
+insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(3,'name3','text3',3,'3','3','3','3','3','3',3,3);
+insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(4,'name4','text4',4,'4','4','4','4','4','4',4,4);
+
+select * from prefix_choice order by 1,2;
+
+rem --------------------------------------------------------
+
+rem
+rem Table structure for table choice_answers
+rem
+
+drop TABLE prefix_choice_answers;
+CREATE TABLE prefix_choice_answers (
+  id number(10) primary key,
+  choice number(10) default '0' not null,
+  userid number(10) default '0' not null,
+  answer number(4) default '0' not null,
+  timemodified number(10) default '0' not null
+);
+
+comment on table prefix_choice_answers is 'Answers for each choice';
+
+drop sequence p_choice_answers_seq;
+create sequence p_choice_answers_seq;
+
+create or replace trigger p_choice_answers_trig
+  before insert on prefix_choice_answers
+  referencing new as new_row
+  for each row
+  begin
+    select p_choice_answers_seq.nextval into :new_row.id from dual;
+  end;
+.
+/
+
+insert into prefix_choice_answers (choice,userid,answer,timemodified) values(1,1,1,1);
+insert into prefix_choice_answers (choice,userid,answer,timemodified) values(2,2,2,2);
+insert into prefix_choice_answers (choice,userid,answer,timemodified) values(3,3,3,3);
+insert into prefix_choice_answers (choice,userid,answer,timemodified) values(4,4,4,4);
+
+select * from prefix_choice_answers order by 1,2;
+
+rem
+rem Dumping data for table log_display
+rem
+
+delete from prefix_log_display where module = 'choice';
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'view', 'choice', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'update', 'choice', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'add', 'choice', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'report', 'choice', 'name');
+
+    
+
+
index e8d8d15..605ee0c 100644 (file)
@@ -1,8 +1,8 @@
-<div align="center">\r
-<table>\r
-<tr><td>Title: </td><td>[[title]]</td></tr>\r
-<tr><td>Caption: </td><td>[[caption]]</td></tr>\r
-</table>\r
-<hr>\r
-[[image]]\r
+<div align="center">
+<table>
+<tr><td>Title: </td><td>[[title]]</td></tr>
+<tr><td>Caption: </td><td>[[caption]]</td></tr>
+</table>
+<hr>
+[[image]]
 </div>
\ No newline at end of file
index 5274dda..ad34826 100644 (file)
@@ -1,41 +1,41 @@
-/******  List View CSS ******/\r
-\r
-#pictures {\r
-  width: 750px;\r
-}\r
-\r
-.picture {\r
-  padding: 5px;\r
-  border-style: solid;\r
-  border-width: thin;\r
-  border-color: #779;\r
-  background-color: white;\r
-\r
-  display:table-cell;display:inline-table;display:inline-block;\r
-}\r
-\r
-.pictureframe {\r
-  padding: 5px;\r
-\r
-  display:table-cell;display:inline-table;display:inline-block;\r
-}\r
-\r
-.picturediv {\r
-  display: inline;\r
-  width: 150px;\r
-  height: 200px;\r
-}\r
-\r
-.inline {\r
-  display: inline;\r
-}\r
-\r
-/*****  Single View CSS *****/\r
-\r
-.caption {\r
-  font-style: italic;\r
-}\r
-\r
-#singleimage {\r
-  width: 700px;\r
+/******  List View CSS ******/
+
+#pictures {
+  width: 750px;
+}
+
+.picture {
+  padding: 5px;
+  border-style: solid;
+  border-width: thin;
+  border-color: #779;
+  background-color: white;
+
+  display:table-cell;display:inline-table;display:inline-block;
+}
+
+.pictureframe {
+  padding: 5px;
+
+  display:table-cell;display:inline-table;display:inline-block;
+}
+
+.picturediv {
+  display: inline;
+  width: 150px;
+  height: 200px;
+}
+
+.inline {
+  display: inline;
+}
+
+/*****  Single View CSS *****/
+
+.caption {
+  font-style: italic;
+}
+
+#singleimage {
+  width: 700px;
 }
\ No newline at end of file
index cc0db77..1d9adf5 100644 (file)
@@ -1,41 +1,41 @@
-var maxHeight = 550;\r
-var maxListHeight = 120;\r
-\r
-function init() {\r
-       if (document.getElementById("singleimage")) single();\r
-       /*else if (document.getElementById("pictures")) list();*/\r
-}\r
-\r
-function list() {\r
-       imageDivs = document.getElementsByName("listimage");\r
-       for (i=0; i < imageDivs.length; i++) {\r
-               currentHeight = imageDivs[i].offsetHeight;\r
-               currentWidth = imageDivs[i].offsetWidth;\r
-               \r
-               if (currentHeight > maxListHeight) {\r
-                       ratio = maxListHeight / currentHeight;\r
-                       imageDivs[i].style.width = (currentWidth*ratio) + 'px';\r
-                       imageDivs[i].style.height = (currentHeight*ratio) + 'px';\r
-                       imageDivs[i].firstChild.style.height = '100%';\r
-                       imageDivs[i].firstChild.style.width = '100%';\r
-               }\r
-       }\r
-}\r
-\r
-function single() {\r
-       var imageDiv = document.getElementById("singleimage");\r
-\r
-       if (imageDiv) {\r
-               currentHeight = imageDiv.offsetHeight;\r
-               currentWidth  = imageDiv.offsetWidth;\r
-               \r
-               if (currentHeight > maxHeight) {\r
-                       ratio = maxHeight / currentHeight;\r
-                       imageDiv.style.width = (currentWidth*ratio) + 'px';\r
-                       imageDiv.style.height = (currentHeight*ratio) + 'px';\r
-               \r
-               }\r
-       }\r
-}\r
-\r
+var maxHeight = 550;
+var maxListHeight = 120;
+
+function init() {
+       if (document.getElementById("singleimage")) single();
+       /*else if (document.getElementById("pictures")) list();*/
+}
+
+function list() {
+       imageDivs = document.getElementsByName("listimage");
+       for (i=0; i < imageDivs.length; i++) {
+               currentHeight = imageDivs[i].offsetHeight;
+               currentWidth = imageDivs[i].offsetWidth;
+               
+               if (currentHeight > maxListHeight) {
+                       ratio = maxListHeight / currentHeight;
+                       imageDivs[i].style.width = (currentWidth*ratio) + 'px';
+                       imageDivs[i].style.height = (currentHeight*ratio) + 'px';
+                       imageDivs[i].firstChild.style.height = '100%';
+                       imageDivs[i].firstChild.style.width = '100%';
+               }
+       }
+}
+
+function single() {
+       var imageDiv = document.getElementById("singleimage");
+
+       if (imageDiv) {
+               currentHeight = imageDiv.offsetHeight;
+               currentWidth  = imageDiv.offsetWidth;
+               
+               if (currentHeight > maxHeight) {
+                       ratio = maxHeight / currentHeight;
+                       imageDiv.style.width = (currentWidth*ratio) + 'px';
+                       imageDiv.style.height = (currentHeight*ratio) + 'px';
+               
+               }
+       }
+}
+
 window.onload = init;
\ No newline at end of file
index 5b245ce..9ff4101 100644 (file)
@@ -1,8 +1,8 @@
-<div class="picturediv">\r
-<table class="pictureframe"><tr><td>\r
-<table class="picture">\r
-<tr><td><div name="listimage">[[image]]</div></td></tr>\r
-<tr><td align="right">##edit## ##delete## ##approve##</td></tr>\r
-</table>\r
-</td></tr></table>\r
-</div>\r
+<div class="picturediv">
+<table class="pictureframe"><tr><td>
+<table class="picture">
+<tr><td><div name="listimage">[[image]]</div></td></tr>
+<tr><td align="right">##edit## ##delete## ##approve##</td></tr>
+</table>
+</td></tr></table>
+</div>
index c6f6f2e..4d9dbae 100644 (file)
@@ -1,2 +1,2 @@
-<div align="center">\r
+<div align="center">
 <div align="center" id="pictures">
\ No newline at end of file
index 07b687c..474d661 100644 (file)
@@ -1,8 +1,8 @@
-<div align="center">\r
-<table id="single">\r
-<tr><td align="center"><h3>[[title]]</h3></td></tr>\r
-<tr><td align="center"><div id="singleimage">[[image]]</div></td></tr>\r
-<tr><td align="center"><span class="caption">[[caption]]</span></td></tr>\r
-<tr><td align="center">##Edit##  ##More##  ##Delete##  ##Approve##</td></tr>\r
-</table>\r
+<div align="center">
+<table id="single">
+<tr><td align="center"><h3>[[title]]</h3></td></tr>
+<tr><td align="center"><div id="singleimage">[[image]]</div></td></tr>
+<tr><td align="center"><span class="caption">[[caption]]</span></td></tr>
+<tr><td align="center">##Edit##  ##More##  ##Delete##  ##Approve##</td></tr>
+</table>
 </div>
\ No newline at end of file
index 86d18a6..d112bb7 100755 (executable)
@@ -214,4 +214,4 @@ INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('forum',
 INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('forum', 'subscribe', 'forum', 'name');
 INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('forum', 'unsubscribe', 'forum', 'name');
 
-select * from prefix_log_display where module = 'forum';\r
+select * from prefix_log_display where module = 'forum';
index de87cbd..3c01ae0 100644 (file)
-<!--\r
-// PLEASE NOTE that this version is more recent than the incorrectly \r
-// numbered v6.1, dated 2003.11.17. From now on, version numbers will \r
-// follow those of Hot Potatoes.\r
-/* hot-potatoes.js (v6.0.4.0 - 2005.02.18)\r
- * =======================================\r
- * by Gordon Bateson, February 2003\r
- * Copyright (c) 2003 Gordon Bateson. All Rights Reserved.\r
- *\r
- * You are hereby granted a royalty free license to use or modify this \r
- * software provided that this copyright notice appears on all copies. \r
- *\r
- * This software is provided "AS IS" without a warranty of any kind.\r
- * \r
- * Documentation and downloads may be available from: \r
- * http://www.kanazawa-gu.ac.jp/~gordon/research/hot-potatoes/\r
- */\r
-// This JavaScript library modifies the SendResults and StartUp functions \r
-// used by hotpot v5 and v6, so that more (or less!) details about the\r
-// student can be input, and more details of a quiz's questions and answers \r
-// can be submitted to the server when the quiz is finished\r
-// If the arrays below (Login, DB, JBC, ...) are set BEFORE calling this \r
-// script, they will NOT be overwritten. Any array that is not set, will \r
-// use the defaults below. This is useful if you want to use different \r
-// settings for different quizzes.\r
-// ************\r
-//  Login Screen\r
-// ************\r
-if (window.Login==null) {\r
-       Login = new Array();\r
-       Login[0] = true;        // Show prompt for user name\r
-                               // This can also be a string of user names ... \r
-                               // Login[0] = "Guest,Peter,Paul,Mary,Webmaster";\r
-                               // or an array of user names (and on-screen texts) (and passwords) ...\r
-                               // Login[0] = new Array("Guest", "001,Peter,xxxx", "002,Paul,yyyy", "003,Mary,zzzz", "Webmaster");\r
-                               // and can also be  written as ...\r
-                               // Login[0] = new Array(\r
-                               //      new Array("Guest"),\r
-                               //      new Array("001", "Peter", "xxxx"),\r
-                               //      new Array("002", "Paul", "yyyy"),\r
-                               //      new Array("003", "Mary", "zzzz"),\r
-                               //      new Array("Webmaster")\r
-                               // );\r
-       Login[1] = true;        // Show prompt for student's UserID\r
-                               // If there is no password prompt (i.e. Logon[3] is false), this value \r
-                               // will be checked against the password information, if any, in Login[0]\r
-       Login[2] = false;       // Show prompt for student's email\r
-       Login[3] = false;       // Show prompt for quiz password, and check this value against \r
-                               // the password information, if any, in Login[0]\r
-                               // This can also be a string required to start the quiz ...\r
-                               // Login[3] = "password";\r
-       Login[4] = true;        // Show prompt for the cookie expiry date\r
-                               // If false, cookies expire at the end of the current session\r
-       Login[5] = "guest,webmaster"\r
-                               // guest user names (case insensitive) ...  \r
-                               // Login[5] = "guest,webmaster"; \r
-                               // These users do NOT need to fill in other login fields\r
-                               // and their quiz results are NOT added to the database\r
-       // the Login prompts and error messages \r
-       // are defined in the MSG array (see below)\r
-}\r
-// *********\r
-//  Database (for use with BFormMail)\r
-// *********\r
-if (window.DB==null) {\r
-       DB = new Array();\r
-       DB[0] = true; // append form fields to database on server\r
-                       // If you are NOT using BFormMail's database feature, \r
-                       // set DB[0]=false, and you can then safely ignore DB[1 to 5]\r
-       DB[1] = "/home/gordon/public_html/cgi/hot-potatoes-data"; \r
-                       // append_db folder path (no trailing slash)\r
-                       // Can be either an absolute path  e.g. "/home/gordon/public_html/cgi/hot-potatoes-data"\r
-                       // or a relative (to CGI bin) path  e.g. "hot-potatoes-data"\r
-       DB[2] = "hot-potatoes"; \r
-                       // append_db file name (no extension)\r
-                       // If left blank, the quiz file name, without extension, will be used\r
-                       // i.e. each quiz will have its results stored in a different file.\r
-                       // If filled in, this file will store the results for ALL quizzes.\r
-                       // Database files and folders must be set up BEFORE running the quiz \r
-                       // must have appropriate access privileges (on Unix, use "chmod 666").\r
-       DB[3] = ""; // append_db extension (if left blank, ".txt" will be used)\r
-       DB[4] = ""; // db_fields (if left blank, ALL quiz fields will be sent)\r
-       DB[5] = ""; // db_delimiter (if left blank, tab will be used)\r
-       DB[6] = "REMOTE_ADDR,HTTP_USER_AGENT"; \r
-                       // env_report ('REMOTE_ADDR','HTTP_USER_AGENT' and a few others)\r
-       // for a complete description of these fields are, see ... \r
-       // http://www.infosheet.com/stuff/BFormMail.readme\r
-       // Switches DB[7] and DB[8] force the settings in the ResultForm\r
-       // In v5 and v6 quizzes, these settings wil be override those in the original quiz\r
-       // If the quiz results are to be sent to an LMS (via the "store" form)\r
-       // then switches DB[7] and DB[8] are not used\r
-       DB[7] = '';     // URL of form processing script\r
-                       // e.g. http://www.kanazawa-gu.ac.jp/~gordon/cgi/bformmail.cgi\r
-       DB[8] = '';     // email address to which results should be sent\r
-                       // e.g. gordon@kanazawa-gu.ac.jp\r
-}\r
-// By default the quiz's question's scores will be returned. \r
-// If you want more detailed information, set the flags below:\r
-// ********\r
-//  JBC\r
-// ********\r
-if (window.JBC==null) {\r
-       JBC = new Array();\r
-       JBC[0] = true;  // show separator line between answers on email\r
-       JBC[1] = true;  // show number of attempts to answer question\r
-       JBC[2] = true;  // show question texts\r
-       JBC[3] = true;  // show right answer(s)\r
-       JBC[4] = true;  // show wrong answer(s)\r
-       JBC[5] = true;  // show ignored answer(s)\r
-       JBC[6] = false; // show answer as text (false) or number (true)\r
-}\r
-// JBC quizzes use the global variables 'I' and 'Status'\r
-// I : an array of JBC_QUESTIONs (one for each question)\r
-// JBC_QUESTION :\r
-//     [0] : question text\r
-//     [1] : array of JBC_ANSWERs (one for each answer)\r
-//     [2] : single/multi flag\r
-//             0 : single answer (using 'button')\r
-//             1 : multiple answers (using 'checkbox')\r
-// JBC_ANSWER :\r
-//     [0] : answer text\r
-//     [1] : answer feedback\r
-//     [2] : correct answer flag\r
-//             0 : this is NOT the correct answer\r
-//             1 : this is the correct answer\r
-// Status : an array of JBC_QUESTION_STATUSes\r
-// JBC_QUESTION_STATUS:\r
-//     [0] : correctly answered yet flag\r
-//             0 : this question has NOT been correctly answered\r
-//             1 : this question has been correctly answered\r
-//     [1] : array of JBC_ANSWER_STATUSes (one for each answer)\r
-//             '0' : initial value\r
-//             'R' : single answer question was answered 'R'ight\r
-//             'W' : single answer question was answered 'W'rong\r
-//             'C' : multiple answer question's checkbox was 'C'hecked\r
-//             'U' : multiple answer question's checkbox was 'U'nchecked\r
-//     [2] : number of times this question has been wrongly answered\r
-//     [3] : score (out of 1) for this question (maybe undefined on HP<5.5)\r
-//             0 : not correct yet\r
-//             0<[3]<1 : correct but only after [2] wrong attempts\r
-//             1 : correct first time (bravo!)\r
-//     N.B. score = (numberOfAnswers - numberofWrongTries) / numberOfAnswers\r
-// ********\r
-//  JCloze\r
-// ********\r
-if (window.JCloze==null) {\r
-       JCloze = new Array();\r
-       JCloze[0] = true;       // show separator line between answers on email\r
-       JCloze[1] = true;       // show student's correct answer\r
-       JCloze[2] = true;       // show other correct answer(s), if any\r
-       JCloze[3] = true;       // show wrong answer(s), if any (NOT available for v5)\r
-       JCloze[4] = false;      // show number of hints + checks (legacy field, replaced by [7]+[9])\r
-       JCloze[5] = false;      // show if clue was asked for or not (legacy field, replaced by [8])\r
-       JCloze[6] = true;       // show clue\r
-       JCloze[7] = true;       // show number of hints (=next letter requests)\r
-       JCloze[8] = true;       // show number of clues\r
-       JCloze[9] = true;       // show number of checks\r
-}\r
-// JCloze quizzes use the global variables 'I' and 'State'\r
-// I : array of JCLOZE_ANSWERs\r
-// JCLOZE_ANSWER :\r
-//     [0] : (unused)\r
-//     [1] : array of JCLOZE_ANSWER_TEXTs\r
-//     [2] : clue for this answer\r
-// JCLOZE_ANSWER_TEXT : \r
-//     [0] : array (seems unnecessary, just the text would be enough?)\r
-//             [0] : text of possible answer\r
-// State : array of JCLOZE_ANSWER_STATEs\r
-// JCLOZE_ANSWER_STATE (v5) : \r
-//     [0] : clue asked for or not\r
-//     [1] : number of hints (show next letter) and penalties ('check' an incorrect answer)\r
-//     [2] : length of answer matched\r
-//     [3] : score for this item\r
-//     [4] : already answered correctly \r
-//     [5] : answer entered in text box (right or not)\r
-// JCLOZE_ANSWER_STATE (v6)\r
-//     this.ClueGiven = false;\r
-//     this.HintsAndChecks = 0;\r
-//     this.MatchedAnswerLength = 0;\r
-//     this.ItemScore = 0;\r
-//     this.AnsweredCorrectly = false;\r
-//     this.Guesses = new Array(); last guess is correct answer\r
-// ********\r
-//  JCross\r
-// ********\r
-if (window.JCross==null) {\r
-       JCross = new Array();\r
-       JCross[0] = true;       // show separator line between answers on email\r
-       JCross[1] = true;       // show number of penalties (hints or checks before complete)\r
-       JCross[2] = true;       // show number of letters\r
-       JCross[3] = true;       // show correct answers\r
-       JCross[4] = true;       // show clues\r
-       JCross[5] = true;       // show wrong answers\r
-       JCross[6] = true;       // show if clue was asked for or not\r
-       JCross[7] = true;       // show number of hints (=next letter requests)\r
-       JCross[8] = true;       // show number of checks\r
-       // there are no "ignored" answers for JCross quizzes\r
-}\r
-// JCross quizzes use the following global variables: \r
-//     L : letters (of correct answers)\r
-//     C : clue numbers (CL in v6)\r
-//     G : guesses\r
-// 'L', 'C' ('CL') and 'G' are all 2-dimensional arrays (rows x cols)\r
-//\r
-// v5 quizzes additionally use the following single-dimension arrays\r
-//     A : clues for across (horizontal) words \r
-//     D : clues for down (vertical) words \r
-// N.B. form is only sent when all answers are correct so \r
-// you can't find out what 'wrong' answers were entered\r
-// ********\r
-//  JMatch\r
-// ********\r
-if (window.JMatch==null) {\r
-       JMatch = new Array();\r
-       JMatch[0] = true;       // show separator line between answers on email\r
-       JMatch[1] = false;      // show number of penalties (= total number of checks)\r
-       JMatch[2] = true;       // show LHS texts (the question)\r
-       JMatch[3] = true;       // show correct answers\r
-       JMatch[4] = true;       // show wrong answers\r
-       JMatch[5] = true;       // show checks (per match) [empty or unchanged RHS are not counted]\r
-       // JMatch has no "clue" or "hint" buttons\r
-       // there cannot be any "ignored" answers\r
-}\r
-// v5 JMatch quizzes use the global variables 'I' and 'Status' (and 'RItems')\r
-// v6 JMatch quizzes use only 'Status'\r
-// v6+ JMatch quizzes use 'F' and 'D' (see below)\r
-// I : an array of JMATCH_PAIRs (one for each pair)\r
-// JMATCH_PAIR :\r
-//     [0] : LHS text\r
-//     [1] : RHS text\r
-//     [2] : fixed (=not jumbled) flag\r
-//             0 : not fixed\r
-//             1 : fixed\r
-//     [3] : index in drop down list selection\r
-// Status : an array of JMATCH_PAIR_STATUSes\r
-// JMATCH_PAIR_STATUS:\r
-//     [0] : correctly matched yet flag\r
-//             0 : this pair has NOT been correctly matched\r
-//             1 : this pair has been correctly matched\r
-//     [1] : number of times this item has been wrongly matched\r
-//     v6 quizzes only\r
-//     [2] : id of original SELECT element containing possible matches\r
-//     Note that after matching, this SELECT is removed, so don't try looking for it :-)\r
-// v6+ JMatch quizzes use the global variables 'F' and 'D'\r
-// F : array of JMATCH_FIXED_ITEMs\r
-// JMATCH_FIXED_ITEM:\r
-//     [0] : text\r
-//     [1] : tag\r
-// D : array of JMATCH_DRAGGABLE_ITEMs\r
-// JMATCH_DRAGGABLE_ITEM\r
-//     [0] : text\r
-//     [1] : tag of the F item to which it SHOULD be dragged\r
-//     [2] : tag of the F item to which it was dragged (initally 0)\r
-// N.B. form is only sent when all answers are correct so \r
-// you can't find out what 'wrong' answers were entered\r
-// ********\r
-//  JMix\r
-// ********\r
-if (window.JMix==null) {\r
-       JMix = new Array();\r
-       JMix[0] = true;         // show separator line between answers on email\r
-       JMix[1] = false;        // show number of wrong guesses (replaced by JMix[5])\r
-       JMix[2] = true;         // show right answer\r
-       JMix[3] = true;         // show wrong answer, if any\r
-       JMix[4] = false;        // show answer as text (false) or number (true)\r
-       JMix[5] = true;         // show number of checks\r
-       JMix[6] = true;         // show number of hints (=show next word)\r
-}\r
-// JMix quizzes use the global variables \r
-// 'Segments', 'GuessSequence' and 'Penalties' \r
-// Segments : array of JMix_QUESTIONs\r
-// JMix_QUESTION:\r
-//     [0] : text\r
-//     [1] : order in sequence\r
-//     [2] : used flag\r
-// GuessSequence : array of 'order in sequence' numbers\r
-// Penalties : number of incorrect guesses\r
-// ********\r
-//  JQuiz\r
-// ********\r
-if (window.JQuiz==null) {\r
-       JQuiz = new Array();\r
-       JQuiz[0] = true;        // show separator line between answers on email\r
-       JQuiz[1] = true;        // show question text\r
-       JQuiz[2] = true;        // show student's correct answer(s)\r
-       JQuiz[3] = false;       // show wrong and ignored answer(s) (legacy field superceded by [8] & [9])\r
-       JQuiz[4] = true;        // show number of hints requested\r
-       JQuiz[5] = false;       // show number of checks of incorrect answers (legacy field superceded by [12])\r
-       // HP6 v6 quizzes only\r
-       JQuiz[6] = false;       // show answer value (false) or A,B,C... index (true)\r
-       JQuiz[7] = true;        // show all students answers\r
-       JQuiz[8] = true;        // show student's wrong answers\r
-       JQuiz[9] = true;        // show ignored answers (not relevant for multi-select questions)\r
-       JQuiz[10] = true;       // show score weightings\r
-       JQuiz[11] = true;       // show question type\r
-       JQuiz[12] = true;       // show number of checks (if true, then JQuiz[5] of will be ignored)\r
-       JQuiz[13] = true;       // show number of times ShowAnswer button was pressed (usually 0 or 1)\r
-}\r
-// v5 JQuiz quizzes use the global variables 'I' and 'Status'\r
-// I : array of JQUIZ_ANSWERs\r
-// JQUIZ_ANSWER :\r
-//     [0] : question text\r
-//     [1] : array of JQUIZ_ANSWER_TEXTs (one for each answer)\r
-// JQUIZ_ANSWER_TEXT :\r
-//     [0] : array (seems unnecessary, just the text would be enough?)\r
-//             [0] : text of possible answer\r
-// Status : array of JQUIZ_ANSWER_STATEs\r
-// JQUIZ_ANSWER_STATE : \r
-//     [0] : question done or not\r
-//     [1] : number of wrong checks\r
-//     [2] : number of hints asked for\r
-//     [3] : student's answer\r
-//     [4] : score for this question\r
-// v6 JQuiz quizzes use the global variables 'I' and 'State'\r
-// I : array of JQUIZ_QUESTIONs\r
-// JQUIZ_QUESTION :\r
-//     [0] : weighting\r
-//     [1] : ?? (always set to '')\r
-//     [2] : question type\r
-//             '0'=multiple-choice, '1'=short-answer, '2'=hybrid, '3'=multi-select\r
-//     [3] : array of JQUIZ_ANSWERSs (one for each possible answer)\r
-// JQUIZ_ANSWER :\r
-//     [0] : answer value\r
-//     [1] : feedback text\r
-//     [2] : correct answer flag (1=a correct answer, 0=a wrong answer)\r
-//     [3] : weighted score (as percentage) if correct\r
-//     [4] : flag (usually set to 1, but for hybrid answers that are not \r
-//             to be included in multiple choice options, it is set to 0)\r
-// State : array of JQUIZ_QUESTION_STATEs\r
-// JQUIZ_QUESTION_STATE : \r
-//     [0] : score (-1 shows not done yet)\r
-//     [1] : array showing on which number try each JQUIZ_ANSWER was selected\r
-//     [2] : number of attempts at this question\r
-//     [3] : total of weighted scores of correct answers that were selected\r
-//             i.e. each time a correct answer is selected, \r
-//             its JQUIZ_ANSWER[3] weighting is added to this total\r
-//             so when all the correct answers have been selected, this will be 100\r
-//     [4] : penalties incurred for hints (score is set to zero if >= 1)\r
-//     [5] :   - for multiple choice, short-answer and hybrid questions, this is a\r
-//             comma-delimited list showing order in which answers were chosen\r
-//             - for multi-select fields, this is bar-delimted ('|') list of settings \r
-//             showing whether each checkbox was selected ('Y') on not ('N') when the \r
-//             'Check' button was clicked. The final item in the list will be the \r
-//             settings for the correct answer.\r
-// N.B. JBC, JMatch(v5) and JQuiz(v5) all use global variables 'I' and 'Status'\r
-//     JBC : I[0].length==3 && !window.RItems\r
-//     JQuiz(v5) : I[0].length==2\r
-//     JMatch(v5) : I[0].length==4 && window.RItems\r
-// N.B. JCloze(v5+6) and JQuiz(v6) both use global variables 'I' and 'State'\r
-//     JCloze (v5) : I[0].length==3 && State[0].Guesses==null\r
-//     JCloze (v6) : I[0].length==3 && State[0].Guesses!=null\r
-//     JQuiz  (v6) : I[0].length==4\r
-// **********\r
-//  Rhubarb\r
-// **********\r
-if (window.Rhubarb==null) {\r
-       Rhubarb = new Array();\r
-       Rhubarb[0] = true;  // show correct words (so far)\r
-       Rhubarb[1] = true;  // show correct words as count (true) or list (false)\r
-       Rhubarb[2] = true;  // show wrong words\r
-       Rhubarb[3] = false; // show wrong words as count (true) or list (false)\r
-       Rhubarb[4] = false; // show ignored words (not implemented yet)\r
-       Rhubarb[5] = true;  // show hints\r
-}\r
-// **********\r
-//  Sequitur\r
-// **********\r
-if (window.Sequitur==null) {\r
-       Sequitur = new Array();\r
-       Sequitur[0] = true;  // show count of correct button clicks\r
-       Sequitur[1] = true;  // show count of wrong button clicks\r
-}\r
-// **********\r
-//  Messages\r
-// **********\r
-if (window.MSG==null) {\r
-       MSG = new Array();\r
-       // Login prompts\r
-       MSG[0] = 'Name';\r
-       MSG[1] = 'ID';\r
-       MSG[2] = 'Email';\r
-       MSG[3] = 'Password';\r
-       MSG[4] = 'Cookies';\r
-       // Login buttons\r
-       MSG[5] = 'Start the Quiz';\r
-       MSG[6] = 'Cancel';\r
-       // Cookie menu options (only used if Login[4] is true)\r
-       MSG[7] = 'keep for this session only';\r
-       MSG[8] = 'keep for one day';\r
-       MSG[9] = 'keep for one month';\r
-       MSG[10] = 'do NOT keep cookies';\r
-       // Login error messages\r
-       MSG[11] = 'Sorry, you were unable to login. Please try again later.';\r
-       MSG[12] = 'Please fill in all the information.';\r
-       MSG[13] = 'Incorrect Password. Please try again.';\r
-       MSG[14] = 'Incorrect ID. Please try again.';\r
-       MSG[15] = 'Email address does not appear to be valid.';\r
-       // day and month names (used in Start_Time and End_Time)\r
-       MSG[16] = new Array('Sun','Mon','Tue','Wed','Thu','Fri','Sat');\r
-       MSG[17] = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');\r
-       // enable popups\r
-       MSG[18] = 'Please enable pop-up windows on your browser.';\r
-       // browser specific instuctions on how to enable popup windows\r
-       var n = navigator;\r
-       var s = n.userAgent.toLowerCase();\r
-       if (n.appName=='Netscape' && s.indexOf('gecko')>=0) {\r
-               // Netscape 6 and 7\r
-               MSG[18] += '\n\n' + 'Edit->Preferences, ' + (s.indexOf('mac')>=0 ? 'Advanced->Scripts & Plugins' : 'Privacy & Security->Popup Window Controls');\r
-       } else if (s.indexOf('safari')>=0) {\r
-               // Safari\r
-               MSG[18] += '\n\n' + 'on Safari menu, uncheck "Block Pop-Up Windows"';\r
-       } else if (s.indexOf('firebird')>=0) {\r
-               // Firebird\r
-               MSG[18] += '\n\n' + 'Preferences->Web Features, uncheck "Block Pop-Up Windows"';\r
-       } else if (s.indexOf('msie 6')>=0) {\r
-               // IE 6 (WinXP.SP2)\r
-               MSG[18] += '\n\n' + 'Tools->Pop-up Blocker->Turn Off Pop-up Blocker';\r
-       }\r
-}\r
-//if (window.FEEDBACK==null) {\r
-//     FEEDBACK = new Array();\r
-//     FEEDBACK[0] = ''; // url of feedback page/script\r
-//     FEEDBACK[1] = ''; // array of array('teachername', 'value');\r
-//     FEEDBACK[2] = ''; // 'student name' [formmail only]\r
-//     FEEDBACK[3] = ''; // 'email@somewhere.com>' [formmail only]\r
-//     FEEDBACK[4] = ''; // window width\r
-//     FEEDBACK[5] = ''; // window height\r
-//     FEEDBACK[6] = ''; // 'Send a message to teacher' [prompt/button text]\r
-//     FEEDBACK[7] = ''; // 'Title'\r
-//     FEEDBACK[8] = ''; // 'Teacher'\r
-//     FEEDBACK[8] = ''; // 'Message'\r
-//     FEEDBACK[10] = ''; // 'Close this window' [formmail only]\r
-//}\r
-// **********\r
-//  HP array\r
-// **********\r
-HP = new Array();\r
-for (var i=0; i<=8; i++) {\r
-       HP[i] = new Array();\r
-}\r
-// indexes for the HP array (makes the code further down easier to read)\r
-_score   = 0;\r
-_weight  = 1;\r
-_correct = 2;\r
-_wrong   = 3;\r
-_unused  = 4;\r
-_hints   = 5;\r
-_clues   = 6;\r
-_checks  = 7;\r
-_guesses = 8;\r
-// *************\r
-//  Server Fields\r
-// *************\r
-if (window.ServerFields==null) {\r
-       ServerFields = new Array();\r
-       // these fields will be added to the ResultForm and submitted to the CGI script on the server.\r
-       // 'Sort', 'return_link_title', 'return_link_url' and 'print_blank_fields' are useful for formmail\r
-       // override the HP setting of sort fields (forces ALL fields to be displayed)\r
-       ServerFields[0] = new Array('sort', '');\r
-       // add link to close pop-up results window\r
-       ServerFields[1] = new Array('return_link_title', 'Close this window');\r
-       ServerFields[2] = new Array('return_link_url', 'javascript:self.close()');\r
-       // make sure zero values are printed\r
-       ServerFields[3] = new Array('print_blank_fields', 'yes');\r
-       // you can also set other fields for your customized CGI script\r
-       // e.g. adding a server defined start time (instead of a client defined start time)\r
-       // ServerFields[4] = new Array('serverStartTime', '<?php echo date("Y-m-d H:i:s") ?>');\r
-}\r
-// *********************\r
-//      Login screen\r
-//  (not required by LMS)\r
-// *********************\r
-function QuizLogin(LoginPrompt) {\r
-       if (!is_LMS() && (Login[0] || Login[1] || Login[2] || Login[3])) {\r
-               var html = ''\r
-                       + '<html>'\r
-                       + '<head></head>'\r
-                       + '<body bgColor="#cccccc" onLoad="opener.setFocus(self)">'\r
-                       + '<form onSubmit="'\r
-                       +       'self.ok=true;'\r
-                       +       'self.expiry=null;'\r
-               ;\r
-               if (Login[4]) { // cookie expiry\r
-                       html += "opener.checkOK(self,'CookieExpiry');";\r
-               }\r
-               if (Login[0]) { // user name\r
-                       html += "opener.checkOK(self,'UserName');";\r
-               }\r
-               if (Login[1]) { // user ID\r
-                       html += "opener.checkOK(self,'UserID');";\r
-               }\r
-               if (Login[2]) { // user email\r
-                       html += "opener.checkOK(self,'UserEmail');";\r
-               }\r
-               if (Login[3]) { // quiz password\r
-                       html += "opener.checkOK(self,'Password');";\r
-               }\r
-               html +=          'if(ok){'\r
-                       +               'opener.StartQuiz();'\r
-                       +               'self.close();'\r
-                       +         '}else{'\r
-                       +               'if(isNaN(self.tries))self.tries=0;'\r
-                       +               'self.tries++;'\r
-                       +               'if(self.tries<3){'\r
-                       +                       'opener.setFocus(self);'\r
-                       +               '}else{'\r
-                       +                       "alert(opener.MSG[11]);"\r
-                       +                       'opener.goBack();'\r
-                       +                       'self.close();'\r
-                       +               '}'\r
-                       +         '}'\r
-                       +         'return false;'\r
-                       + '">'\r
-               ;\r
-               html += '<table>'\r
-                       +       '<caption>' + LoginPrompt + '</caption>';\r
-               ;\r
-               if (Login[0]) { // user name\r
-                       var v = getCookie(self, 'UserName');\r
-                       html += '<tr>'\r
-                               +       '<th align=right nowrap>' + MSG[0] + ' :</th>'\r
-                               +       '<td>'\r
-                       ;\r
-                       if (typeof(Login[0])=='boolean') { // text box\r
-                               html += '<input type=text name=UserName value="' + v + '">';\r
-                       } else { // drop down menu of names\r
-                               // pattern to match commas and white space\r
-                               var comma = (window.RegExp) ? new RegExp('\\s*,\\s*') : ',';\r
-                               // convert list of names to array, if necessary\r
-                               if (typeof(Login[0])=='string') {\r
-                                       Login[0] = Login[0].split(comma);\r
-                               }\r
-                               html += '<select name=UserName size=1>'\r
-                                       + '<option value=""></option>'\r
-                               ;\r
-                               for(var i=0; i<Login[0].length; i++) {\r
-                                       // convert name details to array if nececount_cary\r
-                                       if (typeof(Login[0][i])=='string') {\r
-                                               Login[0][i] = Login[0][i].split(comma);\r
-                                       }\r
-                                       html += makeOption(Login[0][i][0], v, Login[0][i][1]);\r
-                               }\r
-                               html += '</select>';\r
-                       }\r
-                       html +=         '</td>'\r
-                               + '</tr>'\r
-                       ;\r
-               }\r
-               if (Login[1]) { // user ID\r
-                       var v = getCookie(self, 'UserID');\r
-                       html += '<tr><th align=right nowrap>' + MSG[1] + ' :</th><td><input type=text name=UserID value="' + v + '"></td></tr>';\r
-               }\r
-               if (Login[2]) { // user email\r
-                       var v = getCookie(self, 'UserEmail');\r
-                       html += '<tr><th align=right nowrap>' + MSG[2] +' :</th><td><input type=text name=UserEmail value="' + v + '"></td></tr>';\r
-               }\r
-               if (Login[3]) { // quiz password\r
-                       var v = getCookie(self, 'Password');\r
-                       html += '<tr><th align=right nowrap>' + MSG[3] + ' :</th><td><input type=password name=Password value="' + v + '"></td></tr>';\r
-               }\r
-               if (Login[4]) { // cookie lifespan\r
-                       var v = getCookie(self, 'CookieExpiry');\r
-                       html += '<tr>'\r
-                               +       '<th align=right nowrap>' + MSG[4] + ' :</th>'\r
-                               +       '<td>'\r
-                               +               '<select name="CookieExpiry" size=1>'\r
-                               +                       makeOption('session', v, MSG[7])\r
-                               +                       makeOption('day', v, MSG[8])\r
-                               +                       makeOption('month', v, MSG[9])\r
-                               +                       makeOption('never', v, MSG[10])\r
-                               +               '</select>'\r
-                               +       '</td>'\r
-                               + '</tr>'\r
-                       ;\r
-               }\r
-               html +=         '<tr>'\r
-                       +               '<th>&nbsp;</th>'\r
-                       +               '<td nowrap>'\r
-                       +                       '<input type=submit value="' + MSG[5] + '"> '\r
-                       +                       '<input type=button value="' + MSG[6] + '" onClick="opener.goBack();self.close();">'\r
-                       +               '</td>'\r
-                       +       '</tr>'\r
-                       + '</table></form></body></html>'\r
-               ;\r
-               // set height of Login Window\r
-               var m = navigator.userAgent.indexOf('Mac')>=0;\r
-               var h = (m ? 80 : 100);\r
-               for (var i=0; i<5; i++) h += (Login[i] ? (m ? 20 : 25) : 0);\r
-               // open up a new window\r
-               if (!openWindow('', '', (m ? 320 : 300), h, 'RESIZABLE', html)) {\r
-                       alert(MSG[18]); // unable to open popup window\r
-               }\r
-       } else { // no Login required\r
-               window.UserName = window.UserID = window.UserEmail = window.Password = '';\r
-               window.StartQuiz();\r
-       }\r
-       return true;\r
-}\r
-function makeOption(value, v, txt) {\r
-       return '<option value="' + value + '"' + (value==v ? ' SELECTED' : '') + '>' + (txt ? txt : value) + '</option>';\r
-}\r
-function setFocus(w) {\r
-       w.focus(); // bring window to the front\r
-       var obj = w.document.forms[0].elements;\r
-       for(var i=0; i<obj.length; i++) {\r
-               var v = getValue(w, i);\r
-               if (v=='' || obj[i].type=='submit') {\r
-                       obj[i].focus();\r
-                       break;\r
-               }\r
-       }\r
-}\r
-function checkOK(w, n){\r
-       var v = getValue(w, n, true);\r
-       if (v || (n!='UserName' && isGuest())) {\r
-               if (n=='CookieExpiry') setCookieExpiry(w, v);\r
-               setCookie(self, n, v, w.expiry);\r
-               if (n!='CookieExpiry') eval('self.' + n + '=v');\r
-       } else {\r
-               if (w.ok) alert(MSG[12]);\r
-               w.ok = false;\r
-       }\r
-}\r
-function getValue(w, n, flag) {\r
-       var obj = w.document.forms[0].elements[n];\r
-       var TYPE = obj.type.toUpperCase(); // required for ns4 (win)\r
-       if (obj.options && TYPE.indexOf('SELECT')>=0){ \r
-               var v = obj.options[obj.selectedIndex].value;\r
-       } else {\r
-               var v = obj.value;\r
-       }\r
-       if (flag) {\r
-               var msg = '';\r
-               if (n=='Password' || (n=='UserID' && !Login[3])) {\r
-                       var pwd = getPassword(w);\r
-                       if (pwd && v!=pwd) msg = MSG[n=='Password' ? 13 : 14];\r
-               } \r
-               if (n=='UserEmail' && window.RegExp) {\r
-                       var r = '(\\w|-)+';\r
-                       r = r + '(\\.' + r + ')';\r
-                       r = new RegExp('^(' + r + '*)@(' + r + '+)$');\r
-                       if (v.match(r)==null) msg = MSG[15];\r
-               }\r
-               if (msg) {\r
-                       obj.value = v = '';\r
-                       if (w.ok) alert(msg);\r
-                       w.ok = false;\r
-               }\r
-       }\r
-       return v;\r
-}\r
-function getPassword(w) {\r
-       var pwd = '';\r
-       if (Login[3] && typeof(Login[3])=='string') {\r
-               pwd = Login[3];\r
-       } else if ((Login[3] || Login[1]) && typeof(Login[0])=='object') {\r
-               var username = getValue(w, 'UserName');\r
-               for(var i=0; i<Login[0].length; i++) {\r
-                       if (username==Login[0][i][0]) {\r
-                               pwd = Login[0][i][2];\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-       return pwd;\r
-}\r
-function setCookieExpiry(w, v) {\r
-       if (v=='never'){\r
-               w.expiry = new Date('Thu, 01-Jan-70 00:00:01 GMT');\r
-       } else if (v=='day' || v=='month') {\r
-               var ms = (v=='month' ? 31 : 1) * 60 * 60 * 24 * 1000;\r
-               w.expiry = new Date((new Date()).getTime() + ms);\r
-       }\r
-}\r
-function setCookie(w, name, value, expires, path, domain, secure) {\r
-       if (name) w.document.cookie = ''\r
-               + 'HP_' + name + "=" + escape(value)\r
-               + (expires ? "; expires=" + expires.toGMTString() : "")\r
-               + (path ? "; path=" + path : "")\r
-               + (domain ? "; domain=" + domain : "")\r
-               + (secure ? "; secure" : "")\r
-       ;\r
-}\r
-function getCookie(w, n) {\r
-       var c = w.document.cookie;\r
-       var i = c.indexOf('HP_' + n + '=');\r
-       var j = (i<0) ? -1 : c.indexOf(';', (i += n.length + 4));\r
-       return (i<0) ? '' : unescape(c.substring(i, ((j<0) ? c.length : j)));\r
-}\r
-function goBack(w) {\r
-       if (w==null) w = self; // default\r
-       if (w.history.length) w.history.back();\r
-}\r
-function openWindow(url, name, width, height, attributes, html) {\r
-       // set height, width and attributes\r
-       if (window.screen && width && height) {\r
-               var W = screen.availWidth;\r
-               var H = screen.availHeight;\r
-               width = Math.min(width, W);\r
-               height = Math.min(height, H);\r
-               attributes = ''\r
-                       + (attributes ? (attributes+',') : '')\r
-                       + 'WIDTH='+width+',HEIGHT='+height\r
-               ;\r
-       }\r
-       // create global hpWindows object, if necessary\r
-       if (!window.hpWindows) window.hpWindows = new Array();\r
-       // initialize window object\r
-       var w = null;\r
-       // has a window with this name been opened before?\r
-       if (name && hpWindows[name]) {\r
-               // http://www.webreference.com/js/tutorial1/exist.html\r
-               if (hpWindows[name].open && !hpWindows[name].closed) {\r
-                       w = hpWindows[name];\r
-                       w.focus();\r
-               } else {\r
-                       hpWindows[name] = null;\r
-               }\r
-       }\r
-       // check window is not already open\r
-       if (w==null) {\r
-               // workaround for "Access is denied" errors in IE when offline\r
-               // based on an idea seen at http://www.devshed.com/Client_Side/JavaScript/Mini_FAQ\r
-               var ie_offline = (document.all && location.protocol=='file:');\r
-               // try and open the new window\r
-               w = window.open((ie_offline ? '' : url), name, attributes);\r
-               // check window opened OK (user may have prevented popups)\r
-               if (w) {\r
-                       // center the window\r
-                       if (window.screen && width && height) {\r
-                               w.moveTo((W-width)/2, (H-height)/2);\r
-                       }\r
-                       // add content, if required\r
-                       if (html) {\r
-                               with (w.document) {\r
-                                       clear();\r
-                                       open();\r
-                                       write(html);\r
-                                       close();\r
-                               }\r
-                       } else if (url && ie_offline) {\r
-                               w.location = url;\r
-                       }\r
-                       if (name) hpWindows[name] = w;\r
-               }\r
-       }\r
-       return w;\r
-}\r
-// *********************\r
-//  Send results by email\r
-//  (not required by LMS)\r
-// *********************\r
-function SendAllResults(Score) {\r
-       // check this quiz is not generated by a LMS\r
-       if (!is_LMS()) {\r
-               // add flat file database details to the results form\r
-               AddDatabaseDetailsToResultForm();\r
-               // add student details to the results form\r
-               AddStudentDetailsToResultForm();\r
-               // add question details to the results form\r
-               AddQuestionDetailsToResultForm();\r
-               // add server fields, if any, to results form\r
-               AddServerFieldsToResultForm();\r
-               // change "method" of form, because "get" only allows 512 byts of data\r
-               ResultForm = replaceLast('method="get"', 'method="post"', ResultForm);\r
-               // create results window and form\r
-               var w = openWindow('', '', 500, 400, 'RESIZABLE,SCROLLBARS,LOCATION', ResultForm);\r
-               // check window opened OK (user may have prevented popups)\r
-               if (w) {\r
-                       // get shortcut to form object\r
-                       var form = w.document.forms[0];\r
-                       // update some important field values\r
-                       form.Score.value = Score + '%';\r
-                       form.realname.value = UserName;\r
-                       form.Start_Time.value = getTime(Start_Time);\r
-                       form.End_Time.value = getTime();\r
-                       // force email subject and Exercise title\r
-                       form.subject.value = document.title;\r
-                       form. Exercise.value = document.title;\r
-                       // update DB fields, if required\r
-                       if (DB[0] && !isGuest()) set_db_fields(form);\r
-                       if (DB[7]) form.action = DB[7];\r
-                       if (DB[8]) form.recipient.value = DB[8];\r
-                       // if this is a Netscape browser, check if the referer will be set OK\r
-                       if (navigator.appName=='Netscape' && (location.protocol=='file:' || navigator.userAgent.indexOf('Netscape6')>=0)) {\r
-                               // ns4 and ns7 set referer to 'file:// ...' when running a quiz offline\r
-                               // ns6.2 (at least) always sets referer to 'about:blank' \r
-                               // Netscape's setting of referer can cause BFormMail\r
-                               // to reject the form, so encode the form data as a URL\r
-                               var url = form.action;\r
-                               var obj = form.elements;\r
-                               for (var i=0; i<obj.length; i++) {\r
-                                       var  v = escape(obj[i].value);\r
-                                       v = v.replace((new RegExp('\\+', 'g')), '%2B');\r
-                                       url += (i==0 ? '?' : '&') + obj[i].name + '=' + v;\r
-                               }\r
-                               w.location.href = url;\r
-                       } else { // browser can POST form ok\r
-                               form.submit();\r
-                       }\r
-               } else { // unable to open popup window\r
-                       alert(MSG[18]);\r
-               }\r
-       } // end if LMS\r
-}\r
-function isGuest() {\r
-       // check username is not a "guest" user\r
-       var flag = false;\r
-       var n = getCookie(self, 'UserName').toLowerCase();\r
-       if (n) {\r
-               // convert list of user names to array, if necessary\r
-               if(typeof(Login[5])=='string') {\r
-                       Login[5] = Login[5].split(',');\r
-               }\r
-               for(var i=0; i<Login[5].length; i++) {\r
-                       if (n==Login[5][i].toLowerCase()) {\r
-                               flag = true;\r
-                               break;\r
-                       }\r
-               }\r
-       }\r
-       return flag;\r
-}\r
-function set_db_fields(form) {\r
-       // update list of DB fields, if required\r
-       if (DB[4]=='' && window.RegExp) {\r
-               // add administration fields\r
-               var db_fields = ''\r
-                       + 'subject,realname'\r
-                       + (Login[1] ? ',ID' : '')\r
-                       + (Login[2] ? ',email' : '')\r
-                       + (Login[3] ? ',password' : '')\r
-                       + ',Score,Start_Time,End_Time'\r
-               ;\r
-               // add answer fields (except separators)\r
-               var r = new RegExp('^[^_]+_q\\d\\d_\\w+$');\r
-               for(var i=0; i<form.elements.length; i++) {\r
-                       var n = form.elements[i].name;\r
-                       if (r.test(n)) db_fields += ',' + n;\r
-               }\r
-               form.db_fields.value = db_fields;\r
-       }\r
-       // make sure delimiter is set (NS6+ requires this be set here, not any earlier)\r
-       form.db_delimiter.value = (DB[5] ? DB[5] : '\t');\r
-}\r
-function AddStudentDetailsToResultForm() {\r
-       var sDetails = '';\r
-       if (Login[0]) { // user name\r
-               // use 'realname' instead of a separate 'Name' field\r
-               // sDetails += hpHiddenField('Name', window.UserName);\r
-       }\r
-       if (Login[1]) { // user ID\r
-               sDetails += hpHiddenField('ID', window.UserID);\r
-       }\r
-       if (Login[2]) { // user email\r
-               sDetails += hpHiddenField('email', window.UserEmail);\r
-       }\r
-       if (sDetails && window.RegExp) {\r
-               // insert sDetails before '<input...Score...></input>'\r
-               var r = new RegExp('<input[^>]*Score[^>]*><\\/input>', 'i');\r
-               var m = r.exec(ResultForm);\r
-               if (m) {\r
-                       ResultForm = ResultForm.replace(m[0], sDetails + m[0] + makeSeparator('Time_'));\r
-                       sDetails = '';\r
-               }\r
-       }\r
-       if (Login[3]) { // quiz password\r
-               sDetails += hpHiddenField('Password', window.Password);\r
-               ResultForm = replaceLast('</form>', sDetails + '</form>', ResultForm);\r
-       }\r
-}\r
-function AddQuestionDetailsToResultForm() {\r
-       var qDetails = GetQuestionDetails();\r
-       if (qDetails) {\r
-               // insert qDetails before the final </form> tag in the ResultForm\r
-               ResultForm = replaceLast('</form>', qDetails + '</form>', ResultForm);\r
-       }\r
-}\r
-function AddDatabaseDetailsToResultForm() {\r
-       if (window.DB && DB[0] && !isGuest()) {\r
-               var dbDetails = '';\r
-               var folder = DB[1];\r
-               if (folder && folder.charAt(folder.length-1)!='/') folder += '/';\r
-               var file = DB[2];\r
-               if (file=='') {\r
-                       file = location.href;\r
-                       file= file.substring(file.lastIndexOf('/')+1);\r
-                       var i = file.indexOf('?');\r
-                       if (i >= 0) file = file.substring(0, i);\r
-                       var i = file.lastIndexOf('.');\r
-                       if (i >= 0) file = file.substring(0, i);\r
-               }\r
-               var ext = (DB[3] ? DB[3] : 'txt');\r
-               if (ext.charAt(0)!='.') ext = '.' + ext;\r
-               dbDetails += hpHiddenField('append_db', folder + file + ext);\r
-               dbDetails += hpHiddenField('db_fields', DB[4]);\r
-               dbDetails += hpHiddenField('db_delimiter', ''); // NS6+ requires this be set later\r
-               if (DB[6]) dbDetails += hpHiddenField('env_report', DB[6]);\r
-               // insert dbDetails before the final </form> tag in the ResultForm\r
-               ResultForm = replaceLast('</form>', dbDetails + '</form>', ResultForm);\r
-       }\r
-}\r
-function AddServerFieldsToResultForm() {\r
-       if (window.ServerFields) {\r
-               var s = ''; // input tags for s(erver fields)\r
-               for (var i=0; i<ServerFields.length; i++) {\r
-                       if (ServerFields[i][0] && window.RegExp) {\r
-                               // remove previous field value, if any\r
-                               var r = new RegExp('<input[^>]*name\\s*=\\s*["\']\\s*' + ServerFields[i][0] + '[^>]*>(\\s*<\\/input>)?', 'i');\r
-                               if (r.test(ResultForm)) {\r
-                                       ResultForm = ResultForm.replace(r, '');\r
-                               }\r
-                       }\r
-                       if (ServerFields[i][1]) {\r
-                               s += hpHiddenField(ServerFields[i][0], ServerFields[i][1]);\r
-                       }\r
-               } // end for\r
-               if (s) ResultForm = replaceLast('</form>', s + '</form>', ResultForm);\r
-       }\r
-}\r
-function replaceLast(a, b, c) {\r
-       // replace last occurrence of 'a' in 'c' with 'b'\r
-       var l = a.length;\r
-       var i = c.lastIndexOf(a);\r
-       return (i<0 || l==0) ? c : (c.substring(0, i) + b + c.substring(i+l));\r
-}\r
-// *************************\r
-//  Extract question details\r
-// *************************\r
-function GetQuestionDetails() {\r
-       var hp = hpVersion();\r
-       var t = hpQuizType();\r
-       var v = hpQuizVersion();\r
-       return  (t==1) ? GetJbcQuestionDetails(hp, v) : \r
-               (t==2) ? GetJClozeQuestionDetails(hp, v) : \r
-               (t==3) ? GetJCrossQuestionDetails(hp, v) : \r
-               (t==4) ? GetJMatchQuestionDetails(hp, v) : \r
-               (t==5) ? GetJMixQuestionDetails(hp, v) : \r
-               (t==6) ? GetJQuizQuestionDetails(hp, v) :\r
-               (t==7) ? GetRhubarbDetails(hp, v) :\r
-               (t==8) ? GetSequiturDetails(hp, v) : '';\r
-}\r
-function GetJbcQuestionDetails(hp, v) {\r
-       qDetails = '';\r
-       // check the quiz version\r
-       if (hp==5 || hp==6) {\r
-               // get question details \r
-               for(var q=0; q<I.length; q++) {\r
-                       // initialize strings to hold answer details\r
-                       var aDetails = new Array();\r
-                       aDetails[0] = new Array(); // right\r
-                       aDetails[1] = new Array(); // wrong\r
-                       aDetails[2] = new Array(); // ignored\r
-                       // get answer details\r
-                       for(var a=0; a<I[q][1].length; a++) {\r
-                               var i = (Status[q][1][a]=='R') ? 0 : (Status[q][1][a]=='0') ? 2 : 1; \r
-                               aDetails[i][aDetails[i].length] = (JBC[6] ? a : I[q][1][a][0]);\r
-                       }\r
-                       // format 'Q' (a padded, two-digit version of 'q')\r
-                       var Q = getQ('JBC', q);\r
-                       // add separator, if required\r
-                       if (JBC[0]) qDetails += makeSeparator(Q);\r
-                       if (JBC[1]) { // number of attempts to answer question\r
-                               qDetails += hpHiddenField(Q+'attempts', Status[q][2] + (Status[q][0]==1 ? 1 : 0));\r
-                       }\r
-                       if (JBC[2]) { // question text\r
-                               qDetails += hpHiddenField(Q+'text', I[q][0]);\r
-                       }\r
-                       if (JBC[3] && (DB[0] || aDetails[0].length>0)) { // right\r
-                               qDetails += hpHiddenField(Q+'right', aDetails[0]);\r
-                       }\r
-                       if (JBC[4] && (DB[0] || aDetails[1].length>0)) { // wrong\r
-                               qDetails += hpHiddenField(Q+'wrong', aDetails[1]);\r
-                       }\r
-                       if (JBC[5] && (DB[0] || aDetails[2].length>0)) { // ignored\r
-                               qDetails += hpHiddenField(Q+'ignored', aDetails[2]);\r
-                       }\r
-                       // calculate score for this question, if required (for HP version < 5.5)\r
-                       if (isNaN(Status[q][3])) {\r
-                               var a1 = Status[q][1].length; // answers\r
-                               var a2 = Status[q][2]; // attempts\r
-                               Status[q][3] =  (a1<1 || a1<(a2-1)) ? 0 : ((a1 - (a2-1)) / a1);\r
-                       }\r
-                       // add 'score' for this question\r
-                       qDetails += hpHiddenField(Q+'score', Math.floor(Status[q][3]*100)+'%');\r
-               } // end for\r
-       }\r
-       return qDetails;\r
-}\r
-function GetJClozeQuestionDetails(hp, v) {\r
-       var qDetails = '';\r
-       // check the quiz version\r
-       if (hp==5 || hp==6) {\r
-               var r = hpRottmeier();\r
-               if (parseInt(r)==2) { // Rottmeier Find-It 3a+3b\r
-                       qDetails += hpHiddenField('JCloze_penalties', window.TotWrongChoices);\r
-               }\r
-               // get details for each question\r
-               var q_max = (r==0) ? State.length :  GapList.length; // could use I.length for both\r
-               for (var q=0; q<q_max; q++) {\r
-                       // format 'Q' (a padded, two-digit version of 'q')\r
-                       var Q = getQ('JCloze', q);\r
-                       // add separator, if required\r
-                       if (JCloze[0]) qDetails += makeSeparator(Q);\r
-                       // score (as %)\r
-                       var x = (hp==5) ? State[q][3] : (r==0) ? State[q].ItemScore : GapList[q][1].Score;\r
-                       qDetails += hpHiddenField(Q+'score', Math.floor(x*100)+'%');\r
-                       var correct = (HP[_correct][q] ? HP[_correct][q] : '');\r
-                       if (JCloze[1]) { // student's correct answer\r
-                               qDetails += hpHiddenField(Q+'correct', correct);\r
-                       }\r
-                       if (JCloze[2]) { // ignored answers\r
-                               var x = new Array();\r
-                               if (r!=2.1) { // exclude Find-It 3a\r
-                                       for (var i=0, ii=0; i<I[q][1].length; i++) {\r
-                                               var s = I[q][1][i][0];\r
-                                               if (typeof(s)=='string' && s!='' && (s.toUpperCase() != correct.toUpperCase())) {\r
-                                                       x[ii++] = s;\r
-                                               }\r
-                                       }\r
-                               }\r
-                               qDetails += hpHiddenField(Q+'ignored', x);\r
-                       }\r
-                       if (JCloze[3]) {\r
-                               var x = (HP[_wrong][q] ? HP[_wrong][q] : '');\r
-                               qDetails += hpHiddenField(Q+'wrong', x);\r
-                       }\r
-                       if (JCloze[4]) { // number of penalties (Hints + Checks)\r
-                               var x = (hp==5) ? State[q][1] : (r==0) ? State[q].HintsAndChecks : (r==1) ?  GapList[q][1].NumOfTrials : (r==2.2) ?  GapList[q][1].HintsAndChecks : 0;\r
-                               qDetails += hpHiddenField(Q+'penalties', x);\r
-                       }\r
-                       if (JCloze[5]) { // clue shown?\r
-                               var x = (hp==5) ? State[q][0] : (r==0) ? State[q].ClueGiven: (r==1) ? GapList[q][1].ClueAskedFor : false;\r
-                               qDetails += hpHiddenField(Q+'clue_shown', (x ? 'YES' : 'NO'));\r
-                       }\r
-                       if (JCloze[6]) { // clue text\r
-                               qDetails += hpHiddenField(Q+'clue_text', I[q][2]);\r
-                       }\r
-                       if (JCloze[7]) { // number of hints\r
-                               var x = (HP[_hints][q] ? HP[_hints][q] : 0);\r
-                               qDetails += hpHiddenField(Q+'hints', x);\r
-                       }\r
-                       if (JCloze[8]) { // number of clues\r
-                               var x = HP[_clues][q] ? HP[_clues][q] : 0;\r
-                               qDetails += hpHiddenField(Q+'clues', x);\r
-                       }\r
-                       if (JCloze[9]) { // number of checks (including the final one for the correct answer)\r
-                               var x = (HP[_checks][q] ? HP[_checks][q] : 0);\r
-                               qDetails += hpHiddenField(Q+'checks', x);\r
-                       }\r
-               } // end for\r
-       }\r
-       return qDetails;\r
-}\r
-function GetJCrossQuestionDetails(hp, v) {\r
-       var qDetails = '';\r
-       // check the quiz version\r
-       if (hp==5 || hp==6) {\r
-               // inialize letter count\r
-               var letters = 0;\r
-               // get details for each question\r
-               for (var row=0; row<L.length; row++) {\r
-                       for (var col=0; col<L[row].length; col++) {\r
-                               // increment letter count, if required\r
-                               if (L[row][col]) letters++; \r
-                               // show answers and clues, if required\r
-                               var q = (hp==5) ? C[row][col] : CL[row][col];\r
-                               if (q) {\r
-                                       for (var i=0; i<2; i++) { // 0==across, 1==down\r
-                                               var AD = (i==0) ? 'A' : 'D';\r
-                                               var acrossdown = (i==0) ? 'across' : 'down';\r
-                                               \r
-                                               var clue = (hp==5) ? eval(AD+'['+q+']') : GetJCrossClue('Clue_'+AD+'_'+q);\r
-                                               if (clue) {\r
-                                                       // format 'Q' (a padded, two-digit version of 'q')\r
-                                                       var Q = getQ('JCross', q) + acrossdown + '_'; // e.g. JCross_01_across_\r
-               \r
-                                                       if (JCross[0]) {\r
-                                                               qDetails += makeSeparator(Q);\r
-                                                       }\r
-                                                       if (JCross[5]) {\r
-                                                               var x = (HP[_correct][AD] && HP[_correct][AD][q]) ? HP[_correct][AD][q] : '';\r
-                                                               qDetails += hpHiddenField(Q+'correct', x);\r
-                                                       }\r
-                                                       if (JCross[4]) qDetails += hpHiddenField(Q+'clue', clue);\r
-                                                       if (JCross[5]) {\r
-                                                               var x = (HP[_wrong][AD] && HP[_wrong][AD][q]) ? HP[_wrong][AD][q] : '';\r
-                                                               qDetails += hpHiddenField(Q+'wrong', x);\r
-                                                       }\r
-                                                       if (JCross[6]) {\r
-                                                               var x = HP[_clues][q] ? HP[_clues][q] : 0;\r
-                                                               qDetails += hpHiddenField(Q+'clues', x);\r
-                                                       }\r
-                                                       if (JCross[7]) {\r
-                                                               var x = (HP[_hints][AD] && HP[_hints][AD][q]) ? HP[_hints][AD][q] : 0;\r
-                                                               qDetails += hpHiddenField(Q+'hints', x);\r
-                                                       }\r
-                                                       if (JCross[8]) {\r
-                                                               var x = (HP[_checks][AD] && HP[_checks][AD][q]) ? HP[_checks][AD][q] : '';\r
-                                                               qDetails += hpHiddenField(Q+'checks', x);\r
-                                                       }\r
-                                               } // end for i\r
-                                       } // end if clue\r
-                               } // end if q\r
-                       } // end for col\r
-               } // end for row\r
-               if (JCross[2]) { // show number of letters\r
-                       qDetails = hpHiddenField('JCross_letters', letters) + qDetails;\r
-               }\r
-               if (JCross[1]) { // show penalties\r
-                       var x = (window.Penalties) ? Penalties : 0;\r
-                       qDetails = hpHiddenField('JCross_penalties', x) + qDetails;\r
-               }\r
-       }\r
-       return qDetails;\r
-}\r
-function GetJCrossClue(id) {\r
-       var obj = (document.getElementById) ? document.getElementById(id) : null;\r
-       return (obj) ? GetTextFromNodeN(obj, 'Clue') : '';\r
-}\r
-function GetJCrossWord(a, r, c, goDown) {\r
-       // a is a 2-dimensional array of letters, r is a row number, c is a column number\r
-       var s = '';\r
-       while (r<a.length && c<a[r].length && a[r][c]) {\r
-               s += a[r][c];\r
-               if (goDown) {\r
-                       r++;\r
-               } else {\r
-                       c++;\r
-               }\r
-       }\r
-       return s;\r
-}\r
-function GetJMatchText(q, className) {\r
-       var obj = (document.getElementById) ? document.getElementById('Questions') : null;\r
-       return (obj) ? GetTextFromNodeN(obj, className, q) : '';\r
-}\r
-function GetJMatchRHS(v, q, getCorrect) {\r
-       var rhs = '';\r
-       if (v==5.1 || v==6.1) { // Drag-and-drop\r
-               var max_i = (window.F && window.D) ? D.length : 0;\r
-               for (var i=0; i<max_i; i++) {\r
-                       if (F[q][1]==D[i][getCorrect ? 1 : 2]) break;\r
-               }\r
-               if (i<max_i) rhs = D[i][0];\r
-       } else if (v==5 || v==6) { // drop-down list of options\r
-               var obj=document.getElementById(Status[q][2]);\r
-               if (obj) { // not correct yet\r
-                       if (getCorrect) {\r
-                               var k = GetKeyFromSelect(obj);\r
-                               var i_max = obj.options.length;\r
-                               for (var i=0; i<i_max; i++) {\r
-                                       if (obj.options[i].value==k) break;\r
-                               }\r
-                               if (i>=i_max) i = 0; // shouldn't happen\r
-                       } else {\r
-                               // get current guess, if any\r
-                               var i = obj.selectedIndex;\r
-                       }\r
-                       if (i) rhs = obj.options[i].innerHTML;\r
-               } else { // correct\r
-                       rhs = GetJMatchText(q, 'RightItem');\r
-               }\r
-       }\r
-       return rhs;\r
-}\r
-function GetJMixQuestionDetails(hp, v) {\r
-       qDetails = '';\r
-       // check the quiz version\r
-       if (hp==5 || hp==6) {\r
-               var q = 0; // question number\r
-               // format 'Q' (a padded, two-digit version of 'q')\r
-               var Q = getQ('JMix', q);\r
-               // add separator, if required\r
-               if (JMix[0]) qDetails += makeSeparator(Q);\r
-               // add 'score' for this question\r
-               var score = HP[_correct]==null ? 0 : ((Segments.length-Penalties)/Segments.length);\r
-               qDetails += hpHiddenField(Q+'score', Math.floor(score*100)+'%');\r
-               if (JMix[1]) { // number of wrong guesses\r
-                       qDetails += hpHiddenField(Q+'wrongGuesses', Penalties);\r
-               }\r
-               if (JMix[2]) { // right answer\r
-                       var x = (HP[_correct][q]) ? HP[_correct][q] : '';\r
-                       qDetails += hpHiddenField(Q+'correct', x);\r
-               }\r
-               if (JMix[3]) { // wrong answer(s)\r
-                       var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';\r
-                       qDetails += hpHiddenField(Q+'wrong', x);\r
-               }\r
-               if (JMix[5]) { // checks\r
-                       var x = (HP[_checks][q]) ? HP[_checks][q] : 0;\r
-                       qDetails += hpHiddenField(Q+'checks', x);\r
-               }\r
-               if (JMix[6]) { // hints\r
-                       var x = (HP[_hints][q]) ? HP[_hints][q] : 0;\r
-                       qDetails += hpHiddenField(Q+'hints', x);\r
-               }\r
-       }\r
-       return qDetails;\r
-}\r
-function GetJMixSequence(indexes) {\r
-       var s = new Array();\r
-       for (var i=0; i<indexes.length; i++) {\r
-               s[i] = JMix[4] ? indexes[i] : GetJMixSegmentText(indexes[i]);\r
-       }\r
-       return s;\r
-}\r
-function GetJMixSegmentText(index){\r
-       var i_max = Segments.length;\r
-       for (var i=0; i<i_max; i++) {\r
-               if (Segments[i][1] == index) break;\r
-       }\r
-       return (i<i_max) ? Segments[i][0] : '';\r
-}\r
-function GetJQuizQuestionDetails(hp, v) {\r
-       var qDetails = '';\r
-       // HP5.5 uses "Status" for v5 and v6 JMatch quizzes (HP6 uses "State")\r
-       // var hp =  (window.Status) ? 5 : (window.State) ? 6 : 0;\r
-       // check the quiz version\r
-       if (hp==5 || hp==6) {\r
-               // get details for each question\r
-               var max_q = (hp==5) ? Status.length : State.length;\r
-               for (var q=0; q<max_q; q++) {\r
-                       // skip this question if it was not used (HP6 v6 only)\r
-                       if (hp==6 && !State[q]) continue;\r
-                       // format 'Q' (a padded, two-digit version of 'q')\r
-                       var Q = getQ('JQuiz', q);\r
-                       // add separator\r
-                       if (JQuiz[0]) qDetails += makeSeparator(Q);\r
-                       if (hp==6 && JQuiz[11]) { // question type\r
-                               var x = parseInt(I[q][2]);\r
-                               x = (x==0) ? 'multiple-choice' : (x==1) ? 'short-answer' : (x==2) ? 'hybrid' : (x==3) ? 'multi-select' : 'n/a';\r
-                               qDetails += hpHiddenField(Q+'type', x);\r
-                       }\r
-                       // score (as %)\r
-                       var x = (hp==5) ? Status[q][4]*10 : I[q][0]*State[q][0];\r
-                       if (x<0) x = 0;\r
-                       qDetails += hpHiddenField(Q+'score', Math.floor(x)+'%');\r
-                       if (hp==6 && JQuiz[10]) { // weighting\r
-                               qDetails += hpHiddenField(Q+'weighting', I[q][0]);\r
-                       }\r
-                       if (JQuiz[1]) { // question text\r
-                               var x = (hp==5) ? I[q][0] : (document.getElementById) ? GetTextFromNodeN(document.getElementById('Q_'+q), 'QuestionText') : '';\r
-                               qDetails += hpHiddenField(Q+'question', x);\r
-                       }\r
-                       if (JQuiz[2]) { // student's correct answers\r
-                               var x = (HP[_correct][q]) ? HP[_correct][q] : '';\r
-                               qDetails += hpHiddenField(Q+'correct', x);\r
-                       }\r
-                       if (JQuiz[3]) { // ignored and wrong answers\r
-                               var x = (hp==5) ? new Array() : GetJQuizAnswerDetails(q, 1);\r
-                               if (hp==5) {\r
-                                       for (var i=0; i<I[q][1].length; i++) {\r
-                                               var correct = HP[_correct][q] ? HP[_correct][q] : '';\r
-                                               if (I[q][1][i][0] && I[q][1][i][0].toUpperCase()!=correct.toUpperCase()) {\r
-                                                       x[x.length] = I[q][1][i][0];\r
-                                               }\r
-                                       }\r
-                               }\r
-                               if (DB[0] || x) qDetails += hpHiddenField(Q+'other', x);\r
-                       }\r
-                       if (hp==6 && JQuiz[7]) { // all selected answers\r
-                               var x = GetJQuizAnswerDetails(q, 0);\r
-                               qDetails += hpHiddenField(Q+'selected', x);\r
-                       }\r
-                       if (JQuiz[8]) { // wrong answers\r
-                               var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';\r
-                               qDetails += hpHiddenField(Q+'wrong', x);\r
-                       }\r
-                       if (hp==6 && JQuiz[9]) { // ignored answers\r
-                               var x = GetJQuizAnswerDetails(q, 4);\r
-                               qDetails += hpHiddenField(Q+'ignored', x);\r
-                       }\r
-                       if (JQuiz[4]) { // number of hints\r
-                               var x = (HP[_hints][q]) ? HP[_hints][q] : 0;\r
-                               qDetails += hpHiddenField(Q+'hints', x);\r
-                       }\r
-                       if (JQuiz[5] || JQuiz[12]) { // number of checks\r
-                               if (JQuiz[12]) { // strictly checks only\r
-                                       var x = (HP[_checks][q]) ? HP[_checks][q] : 0;\r
-                               } else { // checks (+ hints in HP6)\r
-                                       var x = (hp==5) ? Status[q][1] : (State[q][2]-1);\r
-                               }\r
-                               qDetails += hpHiddenField(Q+'checks', x);\r
-                       }\r
-                       if (JQuiz[13]) { // ShowAnswer button\r
-                               var x = (HP[_clues][q]) ? HP[_clues][q] : 0;\r
-                               qDetails += hpHiddenField(Q+'clues', x);\r
-                       }\r
-               } // end for\r
-       } // end if\r
-       return qDetails;\r
-}\r
-function GetTextFromNodeN(obj, className, n) {\r
-       // returns the text under the nth node of obj with the target class name\r
-       var txt = '';\r
-       if (obj && className) {\r
-               if (typeof(n)=='undefined') {\r
-                       n = 0;\r
-               }\r
-               var nodes = GetNodesByClassName(obj, className);\r
-               if (n<nodes.length) {\r
-                       txt += GetTextFromNode(nodes[n]);\r
-               }\r
-       }\r
-       return txt;\r
-}\r
-function GetNodesByClassName(obj, className) {\r
-       // returns an array of nodes with the target classname\r
-       var nodes = new Array();\r
-       if (obj) {\r
-               if (className && obj.className==className) {\r
-                       nodes.push(obj);\r
-               } else if (obj.childNodes) {\r
-                       for (var i=0; i<obj.childNodes.length; i++) {\r
-                               nodes = nodes.concat(GetNodesByClassName(obj.childNodes[i], className));\r
-                       }\r
-               }\r
-       }\r
-       return nodes;\r
-}\r
-function GetTextFromNode(obj) {\r
-       // return text in (and under) a single DOM node\r
-       var txt = '';\r
-       if (obj) {\r
-               if (obj.nodeType==3) {\r
-                       txt = obj.nodeValue + ' ';\r
-               }\r
-               if (obj.childNodes) {\r
-                       for (var i=0; i<obj.childNodes.length; i++) {\r
-                               txt += GetTextFromNode(obj.childNodes[i]);\r
-                       }\r
-               }\r
-       }\r
-       return txt;\r
-}\r
-function GetJQuizAnswerDetails(q, flag) {\r
-       // flag : the type of information required about the student's answers\r
-       //      0 : all student's answers\r
-       //      1 : student's wrong and ignored answers\r
-       //      2 : student's correct answers\r
-       //      3 : student's wrong answers\r
-       //      4 : ignored answers\r
-       var x = State[q][5]; //Sequence of answers chosen by number\r
-       if (I[q][2]=='3') { // multi-select\r
-               if (flag==4) {\r
-                       var x = new Array();\r
-               } else {\r
-                       // get required part of 'x' and convert to array\r
-                       var i = x.lastIndexOf('|');\r
-                       var x = x.substring((flag==2 ? (i+1) : 1), ((flag==0 || flag==2) ? x.length : i)).split('|');\r
-               }\r
-               for (var i=0; i<x.length; i++) {\r
-                       var a = new Array();\r
-                       for (var ii=0; ii<x[i].length; ii++) {\r
-                               if (x[i].charAt(ii)=='Y') {\r
-                                       var s = JQuiz[6] ? String.fromCharCode(97+ii) : I[q][3][ii][0];\r
-                                       if (s && s.replace && window.RegExp) {\r
-                                               s = s.replace(new RegExp('\\+', 'g'), '&#43;');\r
-                                       }\r
-                                       a.push(s);\r
-                               }\r
-                       }\r
-                       x[i] = a.join('+');\r
-               }\r
-       } else if (x) { // multiple-choice, short-answer and hybrid \r
-               // remove trailing comma and convert to array\r
-               x = x.substring(0, x.length-1).split(',');\r
-               if (flag) {\r
-                       var a = new Array();\r
-                       if (flag==1 || flag==2 || flag==3) {\r
-                               for (var i=0; i<x.length; i++) {\r
-                                       var ii = I[q][3][(x[i].charCodeAt(0)-65)][2];\r
-                                       if(((flag==1 || flag==2) && ii==1) || (flag==3 && ii==0)) a.push(x[i]);\r
-                               }\r
-                       }\r
-                       if (flag==1) {\r
-                               x = a;\r
-                               a = new Array();\r
-                       }\r
-                       if (flag==1 || flag==4) {\r
-                               for (var i=0; i<I[q][3].length; i++) {\r
-                                       var s = String.fromCharCode(65+i);\r
-                                       for (var ii=0; ii<x.length; ii++) {\r
-                                               if (x[ii]==s) break;\r
-                                       }\r
-                                       if (ii==x.length) a.push(s);\r
-                               }\r
-                       }\r
-                       x = a;\r
-               }\r
-               // convert answer indexes to values, if required\r
-               if (JQuiz[6]==false) {\r
-                       for (var i=0; i<x.length; i++) {\r
-                               var ii = x[i].charCodeAt(0) - 65;\r
-                               x[i] = I[q][3][ii][0];\r
-                       }\r
-               }\r
-       } else {\r
-               x = new Array();\r
-       }\r
-       return x;\r
-}\r
-function GetRhubarbDetails(v) {\r
-       qDetails = '';\r
-       if (v==6) {\r
-               var q = 0; // always zero\r
-               var Q = getQ('Rhubarb', q);\r
-               if (document.title) { // use quiz title as question name\r
-                       qDetails += hpHiddenField(Q+'name', document.title);\r
-               }\r
-               if (Rhubarb[0]) { // correct words\r
-                       var x = (HP[_correct][q]) ? HP[_correct][q] : '';\r
-                       if (Rhubarb[1]) { // count of correct words\r
-                               for (var i=0,ii=0; i<x.length; i++) {\r
-                                       if (x[i]) ii++;\r
-                               }\r
-                               x = ii;\r
-                       }\r
-                       qDetails += hpHiddenField(Q+'correct', x);\r
-               }\r
-               if (Rhubarb[2]) { // wrong words\r
-                       var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';\r
-                       if (Rhubarb[3]) { // count of wrong words\r
-                               x = x.length;\r
-                       }\r
-                       qDetails += hpHiddenField(Q+'wrong', x);\r
-               }\r
-               if (Rhubarb[4]) { // ignored\r
-                       var x = '';\r
-                       qDetails += hpHiddenField(Q+'ignored', x);\r
-               }\r
-               if (Rhubarb[5]) { // hints\r
-                       var x = (HP[_hints][q]) ? HP[_hints][q] : '';\r
-                       qDetails += hpHiddenField(Q+'hints', x);\r
-               }\r
-       }\r
-       return qDetails;\r
-}\r
-function GetSequiturDetails(v) {\r
-       qDetails = '';\r
-       if (v==6) {\r
-               var q = 0; // always zero\r
-               var Q = getQ('Sequitur', q);\r
-               if (document.title) { // use quiz title as question name\r
-                       qDetails += hpHiddenField(Q+'name', document.title);\r
-               }\r
-               if (Sequitur[0]) { // number of correct buttons chosen\r
-                       var x = (HP[_correct][q]) ? HP[_correct][q] : '';\r
-                       qDetails += hpHiddenField(Q+'correct', x);\r
-               }\r
-               if (Sequitur[1]) { // number of wrong buttons chosen\r
-                       var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';\r
-                       qDetails += hpHiddenField(Q+'wrong', x);\r
-               }\r
-       }\r
-       return qDetails;\r
-}\r
-// *********************\r
-//     click event handlers\r
-// *********************\r
-function hpClick(x, args) {\r
-       // x is the button type\r
-       // args is either empty, a single argument, or an array of arguments\r
-       var btn = (x==1) ? 'Hint' : (x==2) ? 'Clue' : (x==3) ? 'Check' : (x==4)  ? 'Enter' : '';\r
-       if (btn) {\r
-               // convert args to array, if necessary\r
-               var t = typeof(args);\r
-               if (t=='object') {\r
-                       // do nothing (args is already an array)\r
-               } else if (t=='undefined') {\r
-                       args = new Array();\r
-               } else {\r
-                       args = new Array(''+args);\r
-               }\r
-               // call handler for this kind of button\r
-               var x = eval('hpClick'+btn+'('+hpVersion()+','+hpQuizType()+','+hpQuizVersion()+',args);');\r
-       }\r
-}\r
-function hpClickHint(hp, t, v, args) {\r
-       if (t==2 || t==5 || t==6 || t==7) { // JCloze, JMix, JQuiz, Rhubarb\r
-               var q = args[0]; // clue/question number\r
-               if (!HP[_hints][q]) HP[_hints][q] = 0;\r
-               HP[_hints][q]++;\r
-       }\r
-       if (t==3) { // JCross\r
-               if (v==6 || v==5) {\r
-                       var q = args[0]; // clue/question number\r
-                       var AD = args[1]; // direction ('A' or 'D')\r
-                       if (!HP[_hints][AD]) HP[_hints][AD] = new Array();\r
-                       if (!HP[_hints][AD][q]) HP[_hints][AD][q] = 0;\r
-                       HP[_hints][AD][q]++;\r
-               }\r
-       }\r
-       return true;\r
-}\r
-function hpClickClue(hp, t, v, args) {\r
-       if (t==2 || t==3 || t==6) { // JCloze or JCross, or JQuiz (ShowAnswer button)\r
-               var q = args[0]; // clue/question number\r
-               if (!HP[_clues][q]) HP[_clues][q] = 0;\r
-               HP[_clues][q]++;\r
-       }\r
-       return true;\r
-}\r
-function hpClickCheck(hp, t, v, args) {\r
-       if (t==2) { // JCloze\r
-               if (v==5 || v==6) {\r
-                       var r = hpRottmeier();\r
-                       var already_correct = 'true';\r
-                       if (r==0) {\r
-                               already_correct = (hp==5) ? 'State[i][4]==1' : 'State[i].AnsweredCorrectly==true';\r
-                       } else if (r==1) { // DropDown\r
-                               already_correct = 'GapList[i][1].GapLocked==true';\r
-                       } else if (r==2.1) { // Find-It 3a\r
-                               already_correct = 'GapList[i][1].ErrorFound==true';\r
-                       } else if (r==2.2) { // Find-It 3b\r
-                               already_correct = 'GapList[i][1].GapSolved==true';\r
-                       }\r
-                       var i_max = I.length;\r
-                       for (var i=0; i<i_max; i++) {\r
-                               if (eval(already_correct)) continue;\r
-                               var g = '';\r
-                               if (r==0 || r==2.2) {\r
-                                       g = GetGapValue(i);\r
-                               } else if (r==1) { // DropDown\r
-                                       if (hp==5) {\r
-                                               g = eval('document.Cloze.Gap'+i+'.value');\r
-                                       } else if (hp==6) {\r
-                                               g = Get_SelectedDropValue(i);\r
-                                       }\r
-                               } else if (r==2.1 && i==args[0]) { // Find-It 3a\r
-                                       g = I[i][1][0][0];\r
-                               }\r
-                               if (g) {\r
-                                       if (!HP[_checks][i]) HP[_checks][i] = 0;\r
-                                       HP[_checks][i]++;\r
-                                       if (!HP[_guesses][i]) HP[_guesses][i] = new Array();\r
-                                       var ii = HP[_guesses][i].length;\r
-                                       // is this a new guess at this gap?\r
-                                       if (ii==0 || g!=HP[_guesses][i][ii-1]) { \r
-                                               HP[_guesses][i][ii] = g;\r
-                                               var G = g.toUpperCase();\r
-       \r
-                                               var ii_max = I[i][1].length;\r
-                                               for (var ii=0; ii<ii_max; ii++) {\r
-                                                       if (window.CaseSensitive) {\r
-                                                               if (g==I[i][1][ii][0]) break;\r
-                                                       } else {\r
-                                                               if (G==I[i][1][ii][0].toUpperCase()) break;\r
-                                                       }\r
-                                               }\r
-       \r
-                                               if (ii==ii_max) { // guess is wrong\r
-                                                       if (!HP[_wrong][i]) HP[_wrong][i] = new Array();\r
-                                                       var ii_max = HP[_wrong][i].length;\r
-                                                       for (var ii=0; ii<ii_max; ii++) {\r
-                                                               if (HP[_wrong][i][ii]==g) break;\r
-                                                       }\r
-                                                       if (ii==ii_max) {\r
-                                                               HP[_wrong][i][ii] = g;\r
-                                                       }\r
-                                               } else { // guess is correct\r
-                                                       HP[_correct][i] = g;\r
-                                               }\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       if (t==3) { // JCross\r
-               if (v==5 || v==6) {\r
-                       var q = args[0]; // clue/question number\r
-                       for (var row=0; row<L.length; row++) {\r
-                               for (var col=0; col<L[row].length; col++) {\r
-                                       var q = (v==5) ? C[row][col] : CL[row][col];\r
-                                       if (q) {\r
-                                               hpClickCheckJCrossV5V6(hp, v, 'A', q, row, col);\r
-                                               hpClickCheckJCrossV5V6(hp, v, 'D', q, row, col);\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       if (t==4) { // JMatch\r
-               var a = new Array();\r
-               var extra = ''; // extra js code to eval(uate)\r
-               var guess = ''; // js code to eval(uate) guess\r
-               var correct = ''; // js code to eval(uate) correct answer\r
-               if (window.D && window.F) {\r
-                       // drag-and-drop, i.e. v5+ and v6+ (HP5 and HP6)\r
-                       a = F;\r
-                       guess = 'GetJMatchRHS(v,i)';\r
-                       correct = 'GetJMatchRHS(v,i,true)';\r
-               } else  if (window.GetKeyFromSelect) {\r
-                       // HP6 v6\r
-                       a = Status;\r
-                       guess = 'GetJMatchRHS(v,i)';\r
-                       correct = 'GetJMatchRHS(v,i,true)';\r
-               } else if (window.GetAnswer) {\r
-                       // HP5 v6,v5\r
-                       a = I;\r
-                       guess = "(I[i][2]==0||I[i][0]=='')?'':GetAnswer(i)";\r
-                       correct = 'I[i][3])';\r
-               } else if (window.Draggables) {\r
-                       // HP5 v4\r
-                       a = Draggables;\r
-                       s = "Draggables[i].correct=='1'";\r
-               } else if (window.CorrectAnswers) {\r
-                       // HP5 v3\r
-                       a = CorrectAnswers;\r
-                       guess = 'document.QuizForm.elements[i*2].selectedIndex';\r
-                       correct = 'CorrectAnswers[i]';\r
-               }\r
-               for (var i=0; i<a.length; i++) {\r
-                       // check this match has not already been finished\r
-                       if (!HP[_correct][i]) {\r
-                               // do extra setup, if necessary\r
-                               if (extra) eval(extra);\r
-                               // get the guess, if any\r
-                               var g = ''+eval(guess);\r
-                               if (g) {\r
-                                       // is the guess correct?\r
-                                       if (g==eval(correct)) {\r
-                                               HP[_correct][i] = g;\r
-                                       } else { // wrong answer\r
-                                               // initialize wrong guess array if necessary\r
-                                               if (!HP[_wrong][i]) HP[_wrong][i] = new Array();\r
-                                               // check to see if the guess is already in the guess array\r
-                                               var i_max = HP[_wrong][i].length;\r
-                                               for (var ii=0; ii<i_max; ii++) {\r
-                                                       if (HP[_wrong][i][ii]==g) break;\r
-                                               }\r
-                                               // add the guess if it was not found\r
-                                               if (ii==i_max) {\r
-                                                       HP[_wrong][i][ii]=g;\r
-                                               } else {\r
-                                                       g = null; // this is not a new answer\r
-                                               }\r
-                                       }\r
-                                       // increment checks for this question, if necessary\r
-                                       if (g) {\r
-                                               if (!HP[_checks][i]) HP[_checks][i] = 0;\r
-                                               HP[_checks][i]++;\r
-                                       }\r
-                               }\r
-                       }\r
-               }\r
-       } // end if JMatch\r
-       if (t==5) { // JMix\r
-               // get question number (always 0)\r
-               var q = args[0];\r
-               // check question has not already been answered correctly\r
-               if (!HP[_correct][q]) {\r
-                       // match current guess against possible correct answers\r
-                       var a_max = Answers.length;\r
-                       for (var a=0; a<a_max; a++) {\r
-                               var i_max = Answers[a].length;\r
-                               for (var i=0; i<i_max; i++) {\r
-                                       if (Answers[a][i] != GuessSequence[i]) break;\r
-                               }\r
-                               if (i==i_max) break; // correct answer was found\r
-                       }\r
-                       // at this point, (a==a_max) means guess is wrong\r
-                       // get array of segment texts in this g(uess)\r
-                       var g = GetJMixSequence(GuessSequence);\r
-                       // convert g(uess) array and to a s(tring)\r
-                       var s = '';\r
-                       var i_max = g.length;\r
-                       for (var i=0; i<i_max; i++) {\r
-                               g[i] = trim(g[i]);\r
-                               if (g[i]!='') {\r
-                                       s += (s=='' ? '' : '+') +  g[i];\r
-                               }\r
-                       }\r
-                       if (s) {\r
-                               if (a==a_max) { // wrong\r
-                                       if (!HP[_wrong][q]) HP[_wrong][q] = new Array();\r
-                                       var i = HP[_wrong][q].length;\r
-                                       HP[_wrong][q][i] = s;\r
-                               } else { // correct\r
-                                       HP[_correct][q] = s;\r
-                               }\r
-                               // increment checks for this question\r
-                               if (!HP[_checks][q]) HP[_checks][q] = 0;\r
-                               HP[_checks][q]++;\r
-                       }\r
-               }\r
-       }\r
-       if (t==6) { // JQuiz\r
-               if (hp==5 || hp==6) {\r
-                       var q = args[0]; // clue/question number\r
-                       if (hp==5) {\r
-                               if (v==5) {\r
-                                       var g = TrimString(eval('BottomFrame.document.QForm' + q + '.Guess').value);\r
-                               } else if (v==6) {\r
-                                       var g = TrimString(eval('document.QForm.Guess').value);\r
-                               }\r
-                       } else  { // HP 6\r
-                               var g = args[1];\r
-                       }\r
-                       // increment check count\r
-                       if (!HP[_checks][q]) HP[_checks][q] = 0;\r
-                       HP[_checks][q]++;\r
-                       if (g) {\r
-                               var G = g.toUpperCase(); // used for shortanswer only\r
-                               var correct_answer = ''; // used for multiselect only\r
-                               // set index of answer array in I (the question array)\r
-                               var ans = (hp==5) ? 1 : 3;\r
-                               var i_max = I[q][ans].length;\r
-                               for (var i=0; i<i_max; i++) {\r
-                                       // is this a (possible) correct answer?\r
-                                       if (hp==5 || (hp==6 && I[q][ans][i][2])) {\r
-                                               if (hp==6 && I[q][2]==3) { // multiselect\r
-                                                       correct_answer += (correct_answer  ? '&#43;' : '') + I[q][ans][i][0];\r
-                                               } else { // multichoice, shortanswer\r
-                                                       if (window.CaseSensitive) {\r
-                                                               if (g==I[q][ans][i][0]) break;\r
-                                                       } else {\r
-                                                               if (G==I[q][ans][i][0].toUpperCase()) break;\r
-                                                       }\r
-                                               }\r
-                                       }\r
-                               }\r
-                               if (i==i_max && g!=correct_answer) { // wrong\r
-                                       if (!HP[_wrong][q]) HP[_wrong][q] = new Array();\r
-                                       var i_max = HP[_wrong][q].length;\r
-                                       for (var i=0; i<i_max; i++) {\r
-                                               if (HP[_wrong][q][i]==g) break;\r
-                                       }\r
-                                       if (i==i_max) HP[_wrong][q][i] = g;\r
-                               } else {\r
-                                       HP[_correct][q] = g;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       if (t==7) { // Rhubarb\r
-               if (hp==6) {\r
-                       var q = 0; // question number (always zero)\r
-                       var g = args[0]; // InputWord from CheckGuess()\r
-                       if (g) {\r
-                               var G = g.toUpperCase();\r
-                               var i_max = Words.length;\r
-                               for (var i=0; i<i_max; i++) {\r
-                                       if (G==Words[i].toUpperCase()) break;\r
-                               }\r
-                               if (i<i_max) { // correct\r
-                                       if (!HP[_correct][q]) HP[_correct][q] = new Array();\r
-                                       HP[_correct][q][i] = g;\r
-                               } else { // wrong\r
-                                       if (!HP[_wrong][q]) HP[_wrong][q] = new Array();\r
-                                       var i_max = HP[_wrong][q].length;\r
-                                       for (var i=0; i<i_max; i++) {\r
-                                               if (G==HP[_wrong][q][i].toUpperCase()) break;\r
-                                       }\r
-                                       if (i==i_max) HP[_wrong][q][i] = g;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       if (t==8) { // Sequitur\r
-               if (hp==6) {\r
-                       var q = 0; // question number (always zero)\r
-                       if (CurrentCorrect==args[0]) { // correct button chosen\r
-                               if (!HP[_correct][q]) HP[_correct][q] = 0;\r
-                               HP[_correct][q]++;\r
-                       } else {\r
-                               if (!HP[_wrong][q]) HP[_wrong][q] = 0;\r
-                               HP[_wrong][q]++;\r
-                       }                       \r
-               }\r
-       }\r
-       return true;\r
-}\r
-function hpClickCheckJCrossV5V6(hp, v, AD, q, row, col) {\r
-       // v is the version of Hot Potatoes\r
-       // AD is the direction ('A' or 'D')\r
-       // make sure HP[_checks] and HP[_correct] are initialized\r
-       if (!HP[_checks][AD]) HP[_checks][AD] = new Array();\r
-       if (!HP[_correct][AD]) HP[_correct][AD] = new Array();\r
-       // get clue, if any\r
-       var clue = (hp==5) ? eval('window.'+AD) : GetJCrossClue('Clue_'+AD+'_' + q);\r
-       // is this a question that has not been answered correctly yet?\r
-       if (clue && !HP[_correct][AD][q]) {\r
-               var check = false;\r
-               var guess = GetJCrossWord(G, row, col, (AD=='D'));\r
-               var correct = GetJCrossWord(L, row, col, (AD=='D'));\r
-               if (guess==correct) {\r
-                       HP[_correct][AD][q] = correct;\r
-                       check = true;\r
-               } else if (guess) {\r
-                       // make sure HP[_wrong] is initialized\r
-                       if (!HP[_wrong][AD]) HP[_wrong][AD] = new Array();\r
-                       if (!HP[_wrong][AD][q]) HP[_wrong][AD][q] = new Array();\r
-                       // check this guess has not been entered before\r
-                       var i_max = HP[_wrong][AD][q].length;\r
-                       for (var i=0; i<i_max; i++) {\r
-                               if (HP[_wrong][AD][q]==guess) break;\r
-                       }\r
-                       // add the guess if it has not been entered before\r
-                       if (i>=i_max) {\r
-                               HP[_wrong][AD][q][i] = guess;\r
-                               check = true;\r
-                       }\r
-               }\r
-               // update HP[_checks], if necessary\r
-               if (check) {\r
-                       if (!HP[_checks][AD]) HP[_checks][AD] = new Array();\r
-                       if (!HP[_checks][AD][q]) HP[_checks][AD][q] = 0;\r
-                       HP[_checks][AD][q]++;\r
-               }\r
-       }\r
-}\r
-function hpClickEnter(hp, t, v, args) {\r
-       if (t==3) { // JCross\r
-               var q = args[0]; // clue/question number\r
-               if (!HP[_enter][q]) HP[_enter][q] = 0;\r
-               HP[_enter][q]++;\r
-       }\r
-       return true;\r
-}\r
-function GetJMatchQuestionDetails(hp, v) {\r
-       var qDetails = '';\r
-       // HP5.5 uses "I" for v5 and v6 JMatch quizzes\r
-       // var hp5 = (window.I) ? true : false;\r
-       // check the quiz version\r
-       if (hp==5 || hp==6) {\r
-               if (JMatch[1] && v==6.1) { // attempts\r
-                       qDetails += hpHiddenField('JMatch_attempts', Penalties+1);\r
-               }\r
-               // get number of questions\r
-               var max_q = (hp==5 || v==6) ? Status.length : F.length;\r
-               // get details for each question\r
-               for (var q=0; q<max_q; q++) {\r
-                       // format 'Q' (a padded, two-digit version of 'q')\r
-                       var Q = getQ('JMatch', q);\r
-                       // add separator, if required\r
-                       if (JMatch[0] && (JMatch[1] || JMatch[2] || JMatch[3])) {\r
-                               qDetails += makeSeparator(Q);\r
-                       }\r
-                       if (JMatch[1] && (hp==5 || v==6)) { // attempts\r
-                               qDetails += hpHiddenField(Q+'attempts', Status[q][1]);\r
-                       }\r
-                       if (JMatch[2]) { // LHS text (the question)\r
-                               var x = (v==5) ? I[q][0] : (v==6) ? GetJMatchText(q, 'LeftItem') : F[q][0];\r
-                               qDetails += hpHiddenField(Q+'lhs', x);\r
-                       }\r
-                       if (JMatch[3]) { // correct answer (if any)\r
-                               var x = HP[_correct][q] ? HP[_correct][q] : '';\r
-                               qDetails += hpHiddenField(Q+'correct', x);\r
-                       }\r
-                       if (JMatch[4]) { // wrong answers (if any)\r
-                               var x = HP[_wrong][q] ? HP[_wrong][q] : '';\r
-                               qDetails += hpHiddenField(Q+'wrong', x);\r
-                       }\r
-                       if (JMatch[5]) { // checks\r
-                               var x = HP[_checks][q] ? HP[_checks][q] : 0;\r
-                               qDetails += hpHiddenField(Q+'checks', x);\r
-                       }\r
-               } // end for\r
-       }\r
-       return qDetails;\r
-}\r
-// *********************\r
-//   library functions\r
-// *********************\r
-function pad(i, l) {\r
-       var s = (i+'');\r
-       while (s.length<l) s = '0' + s;\r
-       return s;\r
-}\r
-function getQ(section, q) {\r
-       // Q is a padded, two-digit version of the question number, 'q', prefixed by 'section'\r
-       return section + '_q' + (q<9 ? '0' : '') + (q+1) + '_';\r
-}\r
-function makeSeparator(Q) {\r
-       return  is_LMS() ? '' : hpHiddenField(Q.substring(0, Q.length-1), '---------------------------------');\r
-}\r
-function hpHiddenField(name, value, comma, forceHTML) {\r
-       var field = '';\r
-       var t = typeof(value);\r
-       if (t=='string') {\r
-               value = encode_entities(value);\r
-       } else if (t=='object') { // array\r
-               var values = value;\r
-               var i_max = values.length;\r
-               value = '';\r
-               if (comma==null) comma = ','; \r
-               for (var i=0; i<i_max; i++) {\r
-                       values[i] = trim(values[i]);\r
-                       if (values[i]!='') {\r
-                               value += (i==0 ? '' : comma) +  encode_entities(values[i]);\r
-                       }\r
-               }\r
-       }\r
-       if (is_LMS() && !forceHTML) {\r
-               if (value && value.indexOf && value.indexOf('<')>=0 && value.indexOf('>')>=0) {\r
-                       value = '<![CDATA[' + value + ']]>';\r
-               }\r
-               field = '<field><fieldname>' + name + '</fieldname><fielddata>' + value + '</fielddata></field>';\r
-       } else {\r
-               field = '<input type=hidden name="' + name + '" value="' + value + '">';\r
-       }\r
-       return field;\r
-}\r
-function trim(s) {\r
-       if (s==null) s = '';\r
-       var i = 0;\r
-       var ii = s.length;\r
-       while (i<ii && s.charAt(i)==' ') {\r
-               i++;\r
-       }\r
-       while (ii>i && s.charAt(ii-1)==' ') {\r
-               ii--;\r
-       }\r
-       return s.substring(i, ii);\r
-}\r
-function encode_entities(s_in) {\r
-       var i_max = (s_in) ? s_in.length : 0;\r
-       var s_out = '';\r
-       for (var i=0; i<i_max; i++) {\r
-               var c = s_in.charCodeAt(i);\r
-               // 34 : double quote .......["] &amp;\r
-               // 38 : single quote .......['] &apos;\r
-               // 43 : plus sign ..........[+]\r
-               // 44 : comma ..............[,]\r
-               // 60 : left angle bracket .[<] &lt;\r
-               // 62 : right angle bracket [>] &gt;\r
-               // >=128 multibyte character\r
-               s_out += (c==43 || c==44 || c>=128) ? ('&#x' + pad(c.toString(16), 4) + ';') : s_in.charAt(i);\r
-       }\r
-       return s_out;\r
-}\r
-// *********************\r
-//     initialization\r
-//       functions\r
-// *********************\r
-function getTime(obj) {\r
-       obj = obj ? obj : new Date();\r
-       // get year, month and day\r
-       //      for an LMS : yyyy-mm-dd\r
-       //      for email  : DayName MonthName dd yyyy\r
-       var s = is_LMS() ? \r
-               obj.getFullYear() + '-' + pad(obj.getMonth()+1, 2) + '-' + pad(obj.getDate(), 2) : \r
-               MSG[16][obj.getDay()] + ' ' + MSG[17][obj.getMonth()] + ' ' + pad(obj.getDate(), 2) + ' ' + obj.getFullYear()\r
-       ;\r
-       // get hours, minutes and seconds (hh:mm:ss)\r
-       s += ' ' + pad(obj.getHours(), 2) + ':' + pad(obj.getMinutes(), 2) + ':' + pad(obj.getSeconds(), 2);\r
-       // get time difference\r
-       //      for an LMS : +xxxx\r
-       //      for email  : GMT+xxxx\r
-       var x = obj.getTimezoneOffset(); // e.g. -540\r
-       if (!isNaN(x)) {\r
-               s += ' ' + (is_LMS() ? '' : 'GMT') + (x<0 ? '+' : '-');\r
-               x = Math.abs(x);\r
-               s += pad(parseInt(x/60), 2) + pad(x - (parseInt(x/60)*60), 2);\r
-       }\r
-       return s;\r
-}\r
-function getFunc(fn) {\r
-       if (typeof(fn)=='string') {\r
-               fn = eval('window.' + fn);\r
-       }\r
-       return (typeof(fn)=='function') ? fn : null;\r
-}\r
-function getFuncCode(fn, extraCode, anchorCode, beforeAnchor) {\r
-       var s = '';\r
-       var obj = getFunc(fn);\r
-       if (obj) {\r
-               s = obj.toString();\r
-               var i1 = s.indexOf('{')+1;\r
-               var i2 = s.lastIndexOf('}');\r
-               if (i1>0 && i1<i2) {\r
-                       s = s.substring(i1, i2);\r
-               }\r
-       }\r
-       if (extraCode) {\r
-               if (anchorCode) {\r
-                       if (beforeAnchor) {\r
-                               s = replaceLast(anchorCode, extraCode + anchorCode, s);\r
-                       } else {\r
-                               s = replaceLast(anchorCode, anchorCode + extraCode, s);\r
-                       }\r
-               } else {\r
-                       if (beforeAnchor) {\r
-                               s = extraCode + s;\r
-                       } else {\r
-                               s = s + extraCode;\r
-                       }\r
-               }\r
-       }\r
-       return s;\r
-}\r
-function getArgsStr(args) {\r
-       // make s(tring) version of function args array\r
-       var s = '';\r
-       var i_max = args.length;\r
-       for (var i=0; i<i_max; i++) {\r
-               s += '"' + args[i] + '",';\r
-       }\r
-       return s;\r
-}\r
-function getFuncArgs(fn, flag) {\r
-       // flag==0 : return args as string\r
-       // flag==1 ; return args as array\r
-       var i = 0;\r
-       var a = new Array();\r
-       var obj = getFunc(fn);\r
-       if (obj) {\r
-               var s = obj.toString();\r
-               var i1 = s.indexOf('(') + 1;\r
-               var i2 = s.indexOf(')', i1);\r
-               // add args to a(rray)\r
-               while (i1>0 && i1<i2) {\r
-                       var i3 = s.indexOf(',', i1); // next comma\r
-                       if (i3<0 || i3>i2) i3 = i2;\r
-                       a[i++] = trim(s.substring(i1, i3));\r
-                       i1 = i3+1;\r
-               }\r
-       }\r
-       return flag ? a : getArgsStr(a);\r
-}\r
-function getPrompt(fn) {\r
-       // the LoginPrompt is the text string in the first prompt(...) statement\r
-       //      v5 : in the StartUp function\r
-       //      v6 : in the GetUserName function\r
-       // Note: netscape uses double-quote as delimiter, others use single quote\r
-       var s = getFuncCode(fn);\r
-       var i1 = s.indexOf('prompt') + 8;\r
-       var i2 = s.indexOf(s.charAt(i1-1), i1); \r
-       var p = (i1>=8 && i2>i1) ? s.substring(i1, i2) : '';\r
-       // make sure browser has decoded the unicode prompt properly\r
-       // this check is mainly for ns4, but there may be others\r
-       if (window.RegExp) {\r
-               var r = new RegExp('u([0-9A-F]{4})');\r
-               var m = r.exec(p);\r
-               while (m) {\r
-                       p = p.replace(m[0], '&#' + parseInt(m[1], 16) + ';');\r
-                       m = r.exec(p);\r
-               }\r
-       }\r
-       return p;\r
-}\r
-function getStartUpCode(fn) {\r
-       // the main initialization code comes from the StartUp function\r
-       //      v5 : the code before "UserName", if any, \r
-       //           and the code after the 2nd subsequent '}'\r
-       //      v6 : the code before and after 'GetUserName();' \r
-       //           i.e. all the code except the call to 'GetUserName();'\r
-       var s = getFuncCode(fn);\r
-       var i1 = s.indexOf('GetUserName();');\r
-       if (i1>=0) { // v6 \r
-               var i2 = i1 + 14;\r
-       } else { // v5\r
-               var i1 = s.indexOf('UserName');\r
-               var i2 = s.indexOf('}', s.indexOf('}', i1+8)+1)+1;\r
-       }\r
-       return (0<i1 && i1<i2) ? s.substring(0, i1) + s.substring(i2) : '';\r
-}\r
-function is_LMS() {\r
-       if (!window.hpCheckedForm) {\r
-               window.hpCheckedForm = true;\r
-               window.hpFoundForm = hpFindForm('store') ? true : false;\r
-       }\r
-       return hpFoundForm;\r
-}\r
-function hpFeedback() {\r
-       if (FEEDBACK[0]) {\r
-               var url = '';\r
-               var html = '';\r
-               if (FEEDBACK[1] && FEEDBACK[2]) { // formmail\r
-                       html += '<html><body>'\r
-                               + '<form action="' + FEEDBACK[0] + '" method="POST">'\r
-                               + '<table border="0">'\r
-                               + '<tr><th valign="top" align="right">' + FEEDBACK[7] + ':</th><td>' + document.title + '</td></tr>'\r
-                               + '<tr><th valign="top" align="right">' + FEEDBACK[8] + ': </th><td>'\r
-                       ;\r
-                       if (typeof(FEEDBACK[1])=='string') {\r
-                               html += FEEDBACK[1] + hpHiddenField('recipient', FEEDBACK[1], ',', true);\r
-                       } else if (typeof(FEEDBACK[1])=='object') {\r
-                               var i_max = FEEDBACK[1].length;\r
-                               if (i_max==1) { // one teacher\r
-                                       html += FEEDBACK[1][0][0] + hpHiddenField('recipient', FEEDBACK[1][0][0]+' &lt;'+FEEDBACK[1][0][1]+'&gt;', ',', true);\r
-                               } else if (i_max>1) { // several teachers\r
-                                       html += '<select name="recipient">';\r
-                                       for (var i=0; i<i_max; i++) {\r
-                                               html += '<option value="'+FEEDBACK[1][i][1]+'">' + FEEDBACK[1][i][0] + '</option>';\r
-                                       }\r
-                                       html += '</select>';\r
-                               }\r
-                       }\r
-                       html += '</td></tr>'\r
-                               +       '<tr><th valign="top" align="right">' + FEEDBACK[9] + ':</th>'\r
-                               +       '<td><TEXTAREA name="message" rows="10" cols="40"></TEXTAREA></td></tr>'\r
-                               +       '<tr><td>&nbsp;</td><td><input type="submit" value="' + FEEDBACK[6] + '">'\r
-                               +       hpHiddenField('realname', FEEDBACK[2], ',', true)\r
-                               +       hpHiddenField('email', FEEDBACK[3], ',', true)\r
-                               +       hpHiddenField('subject', document.title, ',', true)\r
-                               +       hpHiddenField('title', document.title, ',', true)\r
-                               +       hpHiddenField('return_link_title', FEEDBACK[10], ',', true)\r
-                               +       hpHiddenField('return_link_url', 'javascript:self.close()', ',', true)\r
-                               +       '</td></tr></table></form></body></html>'\r
-                       ;\r
-               } else if (FEEDBACK[1]) { // url only\r
-                       if (typeof(FEEDBACK[1])=='object') {\r
-                               var i_max = FEEDBACK[1].length;\r
-                               if (i_max>1) { // several teachers\r
-                                       html += '<html><body>'\r
-                                               + '<form action="' + FEEDBACK[0] + '" method="POST" onsubmit="this.action+=this.recipient.options[this.recipient.selectedIndex].value">'\r
-                                               + '<table border="0">'\r
-                                               + '<tr><th valign="top" align="right">' + FEEDBACK[7] + ':</th><td>' + document.title + '</td></tr>'\r
-                                               + '<tr><th valign="top" align="right">' + FEEDBACK[8] + ': </th><td>'\r
-                                       ;\r
-                                       html += '<select name="recipient">';\r
-                                       for (var i=0; i<i_max; i++) {\r
-                                               html += '<option value="'+FEEDBACK[1][i][1]+'">' + FEEDBACK[1][i][0] + '</option>';\r
-                                       }\r
-                                       html += '</select>';\r
-                                       html += '</td></tr>'\r
-                                               +       '<tr><td>&nbsp;</td><td><input type="submit" value="' + FEEDBACK[6] + '">'\r
-                                               +       '</td></tr></table></form></body></html>'\r
-                                       ;\r
-                               } else if (i_max==1) { // one teacher\r
-                                       url = FEEDBACK[0] + FEEDBACK[1][0][1];\r
-                               }\r
-                       } else if (typeof(FEEDBACK[1])=='string') {\r
-                               url = FEEDBACK[0] + FEEDBACK[1];\r
-                       }\r
-               } else {\r
-                       url = FEEDBACK[0];\r
-               }\r
-               if (url || html) {\r
-                       var w = openWindow(url, 'feedback', FEEDBACK[4], FEEDBACK[5], 'RESIZABLE,SCROLLBARS', html);\r
-                       if (!w) {\r
-                                // unable to open popup window\r
-                               alert(MSG[18]);\r
-                       }\r
-               }\r
-       }\r
-}\r
-// ********************\r
-//     intercept clicks\r
-// ********************\r
-function hpInterceptFeedback() {\r
-       // modify the function which writes feedback\r
-       //      v6: ShowMessage(Feedback)\r
-       //              but Rhubarb prints score in other functions, so use 'CheckFinished'\r
-       //      v5: WriteFeedback(Feedback)\r
-       //      v4: WriteFeedback(Stuff)\r
-       //      v3: WriteFeedback(Feedback) [except JMatch]\r
-       //      v3: CheckAnswer()           [JMatch only]\r
-       var f = '';\r
-       if (window.CheckWord) { // Rhubarb\r
-               f = 'CheckFinished';\r
-               window.FEEDBACK = null;\r
-       } else if (window.ShowText) { // Sequitur\r
-               f = 'CheckAnswer';\r
-               window.FEEDBACK = null;\r
-       } else { // JBC, JCloze, JCross, JMatch, JMix, JQuiz\r
-               f = window.ShowMessage ? 'ShowMessage' : window.WriteFeedback ? 'WriteFeedback' : 'CheckAnswer';\r
-       }\r
-       if (f) {\r
-               var s = getFuncCode(f) + 'Finish();';\r
-               var a = getFuncArgs(f, true);\r
-               if (a[0] && window.FEEDBACK && FEEDBACK[0]) {\r
-                       s = a[0] + "+='<br /><br />" + '<a href="javascript:hpFeedback();">' + FEEDBACK[6] + "</A>';" + s;\r
-               }\r
-               eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');\r
-       }\r
-}\r
-function hpInterceptHints() {\r
-       // modify the function which shows hints\r
-       //      JBC:    none\r
-       //      JCloze  v3-v6: ShowHint()\r
-       //      JCross  v3: Cheat(), v4: ShowHint(), v5-v6[HP5]: ShowHint(Across,x,y,BoxName), v6[HP6]: ShowHint(Across,ClueNum,x,y,BoxId)\r
-       //      JMatch: none\r
-       //      JMix    v5-v6: CheckAnswer(CheckType=1)\r
-       //      JQuiz   v3: CheckAnswer(ShowHint=true, QNum), v4: CheckAnswer(ShowHint=true), v5-v6[HP5]: CheckAnswer(ShowHint=true,QNum), v6[HP6]: ShowHint(QNum)\r
-       var x = ''; // extra code, if any\r
-       if (window.Cheat) {\r
-               // JCross v3 ?\r
-       } else if (window.ShowHint) {\r
-               var f = 'ShowHint';\r
-               var a = getFuncArgs(f, true);\r
-               if (a.length==0) {\r
-                       if (window.FindCurrent) {\r
-                               // JCloze v3-v6\r
-                               x = 'var q=window.Locked?-1:FindCurrent();if(q>=0&&GetHint(q))hpClick(1,q);';\r
-                       } else {\r
-                               // JCross v4\r
-                               // work out which box would have a hint added\r
-                               // work out which question that box is part of using GridMap and WinLetters\r
-                       }\r
-               } else if (a[0]=='Across') {\r
-                       if (a[1]=='ClueNum') {\r
-                               // JCross v6 [HP6]\r
-                               x = "var args=new Array(ClueNum,Across?'A':'D');hpClick(1,args);";\r
-                       } else if (a[1]=='x' && a[2]=='y') {\r
-                               // JCross v5-v6 [HP5]\r
-                               x = "var args=new Array(C[x][y],Across?'A':'D');hpClick(1,args);";\r
-                       }\r
-               } else if (a[0]=='QNum') {\r
-                       // JQuiz v6[HP6]\r
-                       x = 'hpClick(1,QNum);';\r
-               }\r
-       } else if (window.Hint) {\r
-               // Rhubarb\r
-               var f = 'Hint';\r
-               var a = getFuncArgs(f, true);\r
-               x = 'hpClick(1,0);'; // question number is always zero\r
-       \r
-       } else if (window.CheckAnswer) {\r
-               var f = 'CheckAnswer';\r
-               var a = getFuncArgs(f, true);\r
-               if (a[0]=='ShowHint') {\r
-                       if (a[1]=='QNum') {\r
-                               // JQuiz v3, v5-v6[HP5]\r
-                               x = 'if(ShowHint)hpClick(1,QNum);'; \r
-                       } else {\r
-                               // JQuiz v4\r
-                               x = 'if(ShowHint)hpClick(1,QNum-1);'; // QNum is a global variable\r
-                       }\r
-               } else if (a[0]=='CheckType') {\r
-                       // JMix v5-v6\r
-                       x = 'if(CheckType==1)hpClick(1,0);'; // question number is always 0;\r
-               }\r
-       }\r
-       // add the e(x)tra code, if any, to the start of the hint (f)unction\r
-       if (x) {\r
-               var s = getFuncCode(f, x, '', true);\r
-               eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');\r
-       }\r
-}\r
-function hpInterceptClues() {\r
-       // modify the function which shows clues (or ShowAnswers in JQuiz)\r
-       //      JBC:    none\r
-       //      JCloze  v3-v6: ShowClue(ItemNum)\r
-       //      JCross  v3-v4: ShowClue(ClueNum), v5-v6: ShowClue(ClueNum,x,y)\r
-       //      JMatch  none\r
-       //      JMix    none\r
-       //      JQuiz   ShowAnswers(QNum)\r
-       var x = ''; // extra code, if any\r
-       if (window.ShowClue) {\r
-               var f = 'ShowClue';\r
-               var a = getFuncArgs(f, true);\r
-               if (a[0]=='ItemNum') {\r
-                       // JCloze (v3-v6)\r
-                       x = 'if(!window.Locked)hpClick(2,ItemNum);'; // v6 [HP6] uses window.Locked\r
-               } else if (a[0]=='ClueNum') {\r
-                       if (a[1]=='x' && a[2]=='y') {\r
-                               if (window.A && window.D) {\r
-                                       // JCross v5-v6 [HP5]\r
-                                       x = 'if(A[ClueNum]||D[ClueNum])hpClick(2,ClueNum);';\r
-                               } else if (document.getElementById) {\r
-                                       // JCross v6 [HP6]\r
-                                       x = "if(document.getElementById('clue_' + ClueNum)||document.getElementById('Clue_D_' + ClueNum))hpClick(2,ClueNum);";\r
-                               }\r
-                       } else {\r
-                               if (window.AClues && window.DClues) {\r
-                                       // JCross v3-v4\r
-                                       x = 'if(AClues[ClueNum]||DClues[ClueNum])hpClick(2,ClueNum);';\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-       // JQuiz: there is no "ShowClue" function but there is a "ShowAnswer" function\r
-       if (window.ShowAnswers) {\r
-               var f = 'ShowAnswers';\r
-               var a = getFuncArgs(f, true);\r
-               if (window.State) {\r
-                       if (window.ShowMessage) {\r
-                               // JQuiz v6 [HP6]\r
-                               x = 'if(State[QNum][0]<1)hpClick(2,QNum);';\r
-                       } else if (window.WriteFeedback) {\r
-                               // JQuiz v3-v4\r
-                               x = 'if(State[QNum-1][0]<1)hpClick(2,QNum-1);';\r
-                       }\r
-               } else if (window.Status) {\r
-                       // JQuiz v5-v6 [HP5]\r
-                       x = 'if(Status[QNum][0]<0)hpClick(5,QNum);';\r
-               }\r
-       }\r
-       // add the e(x)tra code, if any, to the start of the clue (f)unction\r
-       if (x) {\r
-               var s = getFuncCode(f, x, '', true);\r
-               eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');\r
-       }\r
-}\r
-function hpInterceptChecks() {\r
-       // modify the function which handles checks\r
-       //      JBC:    none\r
-       //      JCloze  CheckAnswers()\r
-       //              NB: Rottmeier Find-It 3a: CheckText(GapState,GapId)\r
-       //      JCross  none\r
-       //      JMatch  HP5 v3, v5, v6: CheckAnswer(), HP5 v4: CheckResults(), HP6: CheckAnswers()\r
-       //      JMix    CheckAnswer(CheckType)\r
-       //      JQuiz \r
-       //              HP5: CheckAnswer(ShowHint, QNum)\r
-       //              HP6: CheckMCAnswer, CheckMultiSelAnswer, CheckShortAnswer\r
-       //      Rhubarb  CheckWord(InputWord)\r
-       //      Sequitur CheckAnswer(Chosen, Btn)\r
-       // HP6 JQuiz has three "Check Answer" functions\r
-       var f = new Array('CheckMCAnswer', 'CheckMultiSelAnswer', 'CheckShortAnswer');\r
-       for (var i=0; i<f.length; i++) {\r
-               if (eval('window.' + f[i])) {\r
-                       var a = getFuncArgs(f[i], true);\r
-                       var x = "";\r
-                       if (f[i]=='CheckMCAnswer') {\r
-                               x += "var args=new Array(QNum,I[QNum][3][ANum][0]);";\r
-                       } else if (f[i]=='CheckShortAnswer') {\r
-                               x += ""\r
-                               + "var obj=document.getElementById('Q_'+QNum+'_Guess');"\r
-                               + "var args=new Array(QNum,obj.value);"\r
-                               ;\r
-                       } else if (f[i]=='CheckMultiSelAnswer') {\r
-                               x += ""\r
-                               + "var g='';"\r
-                               + "for (var ANum=0; ANum<I[QNum][3].length; ANum++){"\r
-                               +       "var obj=document.getElementById('Q_'+QNum+'_'+ANum+'_Chk');"\r
-                               +       "if (obj.checked)g+=(g?'&#43;':'')+I[QNum][3][ANum][0];"\r
-                               + "}"\r
-                               + "var args=new Array(QNum,g);"\r
-                               ;\r
-                       }\r
-                       if (x) {\r
-                               x = "if(!Finished&&State[QNum].length&&State[QNum][0]<0){" + x + "hpClick(3,args)}";\r
-                               var s = getFuncCode(f[i], x, '', true);\r
-                               eval('window.' + f[i] + '=new Function(' + getArgsStr(a) + 's);');\r
-                       }\r
-               }\r
-       }\r
-       var f = ''; // function name\r
-       var x = ''; // extra code, if any\r
-       if (window.CheckAnswer) {\r
-               f = 'CheckAnswer';\r
-               var a = getFuncArgs(f, true);